Unistyles 3.0 styling - C++ powered StyleSheet superset with zero re-renders, theming, breakpoints, variants, dynamic functions, runtime values
Scanned 9/5/2026
Install to Claude Code
npx -y skills add agents-inc/skills --skill mobile-styling-unistyles --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Mobile Styling Unistyles?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/agents-inc-mobile-styling-unistyles-skills)More formats (shields.io, HTML) on the badges page.
---
name: mobile-styling-unistyles
description: Unistyles 3.0 styling - C++ powered StyleSheet superset with zero re-renders, theming, breakpoints, variants, dynamic functions, runtime values
---
# Unistyles 3.0 Patterns
> **Quick Guide:** Unistyles 3.0 is a StyleSheet superset powered by Nitro Modules (C++/JSI). Import `StyleSheet` from `react-native-unistyles` instead of `react-native` -- same API, but with themes, breakpoints, variants, dynamic functions, and runtime values. Zero re-renders: styles update via the Shadow Tree, not React state. Configure with `StyleSheet.configure()` before any `StyleSheet.create()`. Never spread styles (`{...a, ...b}`) -- use array syntax (`[a, b]`). Requires New Architecture (RN 0.78+).
---
<critical_requirements>
## CRITICAL: Before Using This Skill
> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)
**(You MUST import `StyleSheet` from `react-native-unistyles`, NOT from `react-native` -- the Unistyles version is a superset that enables all features)**
**(You MUST call `StyleSheet.configure()` BEFORE any `StyleSheet.create()` -- configure in your entry file before importing components)**
**(You MUST use array syntax `[styles.a, styles.b]` for merging styles -- NEVER spread `{...styles.a, ...styles.b}` as it destroys C++ state)**
**(You MUST NOT use `useUnistyles` hook in regular components -- it forces full re-renders, defeating Unistyles' zero-render architecture)**
**(You MUST pass only serializable arguments to dynamic functions -- strings, numbers, booleans, arrays, objects (no functions or components))**
</critical_requirements>
---
**Auto-detection:** Unistyles, react-native-unistyles, StyleSheet.configure, UnistylesRuntime, UnistylesThemes, UnistylesBreakpoints, useVariants, compoundVariants, ScopedTheme, withUnistyles, useUnistyles, miniRuntime, rt.insets, rt.screen, mq.only, Display, Hide
**When to use:**
- Styling React Native apps that need dynamic theming (light/dark or custom themes)
- Building responsive layouts with breakpoints and media queries across mobile and web
- Creating reusable component variants (size, color, state) without conditional logic
- Accessing runtime device values (insets, screen size, font scale) inside stylesheets
- Migrating from Unistyles 2.x to 3.0
**When NOT to use:**
- Apps that cannot use the New Architecture (requires RN 0.78+, Fabric)
- Expo Go apps (requires development builds with native modules)
- Minimal apps with no theme switching or responsive needs (plain StyleSheet suffices)
- Apps using a utility-class approach (consider a utility-class styling solution instead)
**Key patterns covered:**
- StyleSheet.configure: themes, breakpoints, settings registration
- StyleSheet.create with theme and miniRuntime (rt) access
- Variants and compound variants for reusable component styles
- Dynamic functions with serializable parameters
- Breakpoints, media queries, and Display/Hide components
- Runtime values: insets, screen dimensions, font scale, color scheme
- Scoped themes and adaptive themes
- withUnistyles for third-party component integration
- Style merging with array syntax (never spread)
**Detailed Resources:**
- [examples/core.md](examples/core.md) - StyleSheet setup, theme access, dynamic functions, style merging
- [examples/theming.md](examples/theming.md) - Theme configuration, adaptive themes, scoped themes, runtime switching
- [examples/responsive.md](examples/responsive.md) - Breakpoints, media queries, Display/Hide, runtime values
- [examples/variants.md](examples/variants.md) - Variants, compound variants, boolean variants, component props pattern
- [reference.md](reference.md) - API quick reference, decision frameworks, v2-to-v3 migration
---
<philosophy>
## Philosophy
Unistyles 3.0 is a **StyleSheet superset** -- if you know React Native's `StyleSheet.create`, you know 80% of Unistyles. The remaining 20% is what makes it powerful: themes, responsive breakpoints, variants, and runtime values, all managed in C++ via JSI with **zero React re-renders**.
**How it works:**
1. **Babel plugin** analyzes StyleSheets at build time, detecting dependencies (theme, runtime, breakpoints)
2. **C++ core** reconstructs StyleSheets natively and tracks which styles depend on what
3. **Shadow Tree updates** bypass React entirely -- when a theme changes or the device rotates, only the affected ShadowNodes update their styles directly
**Core principles:**
1. **Zero re-renders** -- No hooks, no context, no state updates for style changes. The C++ core updates the Shadow Tree directly.
2. **StyleSheet superset** -- Same API as React Native's StyleSheet. Replace the import, keep your code.
3. **Type-safe themes** -- TypeScript declarations ensure full autocompletion for theme properties.
4. **Selective recalculation** -- Only styles that depend on a changed value (theme, breakpoint, inset) are recalculated.
5. **Cross-platform** -- Same styles work on iOS, Android, and web (with automatic CSS class generation for web).
**When Unistyles adds value over plain StyleSheet:**
- Multiple themes (dark/light/custom) with instant switching
- Responsive layouts that adapt to screen size, orientation, or device type
- Component variants (primary/secondary, small/large) without conditional style logic
- Runtime-dependent styles (safe area insets, font scale, keyboard height)
</philosophy>
---
<patterns>
## Core Patterns
### Pattern 1: StyleSheet.create with Theme and Runtime
Replace `react-native` import with `react-native-unistyles`. The create function accepts a callback with `theme` and `rt` (miniRuntime) for dynamic styles. Static styles (no theme/runtime) work identically to plain StyleSheet.
```typescript
import { StyleSheet } from "react-native-unistyles";
const styles = StyleSheet.create((theme, rt) => ({
container: {
flex: 1,
backgroundColor: theme.colors.background,
paddingTop: rt.insets.top,
},
text: {
color: theme.colors.typography,
fontSize: rt.fontScale * 16,
},
// Static styles work exactly like plain StyleSheet
separator: {
height: StyleSheet.hairlineWidth,
backgroundColor: "#ccc",
},
}));
```
**Why good:** theme and rt are injected by the C++ core -- no hooks needed, no re-renders when theme or device values change
See [examples/core.md](examples/core.md) for static vs themed vs runtime StyleSheets and the full miniRuntime property list.
---
### Pattern 2: Variants and Compound Variants
Define style variations inside `variants` -- then select them with `styles.useVariants()`. Compound variants apply styles when multiple variant conditions are met simultaneously.
```typescript
const styles = StyleSheet.create((theme) => ({
button: {
paddingHorizontal: 16,
paddingVertical: 8,
borderRadius: 8,
variants: {
color: {
primary: { backgroundColor: theme.colors.primary },
secondary: { backgroundColor: theme.colors.secondary },
},
size: {
sm: { paddingHorizontal: 8, paddingVertical: 4 },
lg: { paddingHorizontal: 24, paddingVertical: 12 },
},
},
compoundVariants: [
{
color: "primary",
size: "lg",
styles: { borderWidth: 2, borderColor: theme.colors.accent },
},
],
},
}));
// In component -- call useVariants to select active variants
styles.useVariants({ color: "primary", size: "lg" });
```
**Why good:** eliminates conditional style objects, compound variants reduce complex if/else chains, TypeScript infers valid variant combinations
See [examples/variants.md](examples/variants.md) for boolean variants, default variants, the component props pattern with `UnistylesVariants`, and multi-style variants.
---
### Pattern 3: Dynamic Functions
When styles depend on component-level values (not just theme/runtime), use dynamic functions. Arguments must be serializable (strings, numbers, booleans, arrays, objects).
```typescript
const styles = StyleSheet.create((theme) => ({
card: (isHighlighted: boolean, index: number) => ({
backgroundColor: isHighlighted
? theme.colors.highlight
: theme.colors.surface,
opacity: index === 0 ? 1 : 0.8,
}),
}));
// In JSX -- call the function with arguments
<View style={styles.card(isHighlighted, index)} />
```
**Why good:** serializable arguments pass to C++ for native recalculation, full TypeScript inference on parameters
See [examples/core.md](examples/core.md) for dynamic function patterns and the serializable constraint.
---
### Pattern 4: Breakpoints and Media Queries
Define breakpoints in `StyleSheet.configure`, then use breakpoint objects or the `mq` utility in styles. At least one breakpoint must start at `0`.
```typescript
// In style definitions -- breakpoint object syntax
const styles = StyleSheet.create((theme) => ({
container: {
flexDirection: {
xs: "column",
md: "row",
},
padding: {
xs: 8,
sm: 16,
lg: 24,
},
},
}));
```
```typescript
// Media query syntax for precise ranges
import { mq } from "react-native-unistyles";
const styles = StyleSheet.create(() => ({
sidebar: {
display: {
[mq.only.width(0, 768)]: "none",
[mq.only.width(768)]: "flex",
},
},
}));
```
**Why good:** breakpoints cascade like CSS (xs applies until sm overrides), mq provides precise range control, web automatically generates CSS media queries
See [examples/responsive.md](examples/responsive.md) for Display/Hide components, landscape/portrait breakpoints, and mixing breakpoints with mq.
---
### Pattern 5: Style Merging (Array Syntax)
Never spread Unistyles objects. Spreading destroys the C++ state that tracks dependencies. Use React Native's array syntax for merging.
```typescript
// CORRECT -- array syntax preserves C++ state
<View style={[styles.container, styles.overlay]} />
<View style={[styles.card, isFocused && styles.focused]} />
// WRONG -- spreading destroys C++ state
<View style={{ ...styles.container, ...styles.overlay }} />
```
**Why bad (spread):** spreading removes the C++ state Unistyles attaches, forcing it to restore state in unpredictable order; triggers dev-mode warnings
See [examples/core.md](examples/core.md) for merging patterns and conditional style application.
---
### Pattern 6: withUnistyles for Third-Party Components
Third-party components that don't expose native views via `ref` cannot benefit from Unistyles' Shadow Tree updates. Wrap them with `withUnistyles` to subscribe to theme and runtime changes.
```typescript
import { withUnistyles } from "react-native-unistyles";
import { BlurHash } from "react-native-blurhash";
// Static mappings -- re-renders only when dependencies change
const UniBlurHash = withUnistyles(BlurHash, (theme) => ({
color: theme.colors.tint,
}));
// Dynamic mappings via uniProps
<UniBlurHash
uniProps={(theme, rt) => ({
color: rt.colorScheme === "dark"
? theme.colors.darkTint
: theme.colors.lightTint,
})}
/>
```
**Why good:** component re-renders only when its dependencies change, not on every theme/runtime update
**When to use:** only for third-party components that don't work with standard Unistyles styles. Regular React Native components (`View`, `Text`, `Pressable`) work without it.
See [examples/core.md](examples/core.md) for uniProps priority and when to choose withUnistyles vs useUnistyles.
</patterns>
---
<decision_framework>
## Decision Framework
### Choosing the Right Styling Approach
```
Does the component need theme colors or runtime values?
|-- NO -> Plain StyleSheet.create (static object, no callback)
+-- YES -> StyleSheet.create((theme, rt) => ...)
|
Does it also need component-local values (props, state)?
|-- YES -> Dynamic function: style: (arg) => ({ ... })
+-- NO -> Static theme/runtime access is enough
Does the style have multiple visual variants (size, color, state)?
|-- YES -> Use variants {} inside the style
| |
| Do combinations of variants need special treatment?
| +-- YES -> Add compoundVariants []
+-- NO -> Regular style properties
Is this a third-party component that doesn't work with Unistyles styles?
|-- Try withUnistyles first (no re-renders)
+-- Only if that fails -> useUnistyles hook (causes re-renders)
```
### Responsive: Breakpoints vs Media Queries vs Display/Hide
| Need | Solution |
| ---------------------------- | --------------------------------------------- |
| Simple per-breakpoint values | Breakpoint object `{ xs: 8, md: 16 }` |
| Precise pixel ranges | `mq.only.width(0, 500)` |
| Show/hide entire components | `<Display mq={...}>` / `<Hide mq={...}>` |
| Orientation-specific styles | Built-in `portrait` / `landscape` breakpoints |
</decision_framework>
---
<red_flags>
## RED FLAGS
**High Priority Issues:**
- Spreading styles `{...styles.a, ...styles.b}` -- destroys C++ state, causes unpredictable style resolution, triggers dev warnings
- Using `useUnistyles` in regular components -- forces full re-renders, defeats the zero-render architecture
- Calling `StyleSheet.create` before `StyleSheet.configure` -- styles won't have access to themes or breakpoints
- Importing `StyleSheet` from `react-native` instead of `react-native-unistyles` -- styles work but lose all Unistyles features (themes, variants, breakpoints)
- Passing non-serializable arguments to dynamic functions (functions, components, Promises) -- arguments are passed to C++ via `folly::dynamic`, non-serializable values crash
**Medium Priority Issues:**
- Setting both `initialTheme` and `adaptiveThemes: true` in configure -- they are mutually exclusive, Unistyles will throw an error
- Missing Babel plugin configuration -- without it, dependency detection, ref borrowing, and scoped variants don't work
- Using `useUnistyles` at the root level -- subscribes the entire app tree to every theme/runtime change
- Defining breakpoints without a `0` value -- at least one breakpoint must be `0` for CSS-like cascading to work
**Gotchas & Edge Cases:**
- The `bottom` inset is NOT dynamic for keyboard -- use `rt.insets.ime` (input method editor) for keyboard-responsive padding
- Babel plugin does NOT support moving functions outside `StyleSheet.create` or reassigning `theme`/`rt` to other variables -- the analysis is scope-bound
- `ScopedTheme` does not work correctly above `Suspense` boundaries -- place it inside suspended components
- Metro Fast Refresh (HMR) does not propagate child changes to parent `ScopedTheme` components -- requires manual refresh
- `withUnistyles` uniProps are lower priority than inline props -- inline props override uniProps, which override global mappings
- Boolean variants use string keys `"true"` and `"false"` -- they are distinct from a `default` variant
- All themes must share the same TypeScript type -- mismatched theme shapes cause type errors
- On web, Unistyles converts theme colors to CSS variables -- theme switching swaps a single class on `<body>`, no JS recomputation
- `UnistylesRuntime` getters are non-reactive outside StyleSheet -- use `useUnistyles` or `withUnistyles` for reactive access in components
- `StyleSheet.addChangeListener()` (v3.1.0+) is the escape hatch for animation libraries that need runtime update notifications
</red_flags>
---
<critical_reminders>
## CRITICAL REMINDERS
> **All code must follow project conventions in CLAUDE.md**
**(You MUST import `StyleSheet` from `react-native-unistyles`, NOT from `react-native` -- the Unistyles version is a superset that enables all features)**
**(You MUST call `StyleSheet.configure()` BEFORE any `StyleSheet.create()` -- configure in your entry file before importing components)**
**(You MUST use array syntax `[styles.a, styles.b]` for merging styles -- NEVER spread `{...styles.a, ...styles.b}` as it destroys C++ state)**
**(You MUST NOT use `useUnistyles` hook in regular components -- it forces full re-renders, defeating Unistyles' zero-render architecture)**
**(You MUST pass only serializable arguments to dynamic functions -- strings, numbers, booleans, arrays, objects (no functions or components))**
**Failure to follow these rules will cause broken styles, unnecessary re-renders, and runtime crashes from the C++ core.**
</critical_reminders>
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!