/unistyles-v2-to-v3-migration
Migrate react-native-unistyles from v2 to v3. Triggers on: "migrate unistyles", "upgrade unistyles", "v2 to v3", "unistyles migration", "update unistyles", "convert unistyles v2". Covers all API changes including StyleSheet.create, useStyles removal, theme configuration,
$ npx -y skills add jpudysz/react-native-unistyles --skill unistyles-v2-to-v3-migration --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/unistyles-v2-to-v3-migration
Context preview
The summary Claude sees to decide when to auto-load this skill.
Migrate react-native-unistyles from v2 to v3. Triggers on: "migrate unistyles", "upgrade unistyles", "v2 to v3", "unistyles migration", "update unistyles", "convert unistyles v2". Covers all API changes including StyleSheet.create, useStyles removal, theme configuration,
SKILL.md
unistyles-v2-to-v3-migration.SKILL.mdname: unistyles-v2-to-v3-migration
description: >
Migrate react-native-unistyles from v2 to v3. Triggers on: "migrate unistyles",
"upgrade unistyles", "v2 to v3", "unistyles migration", "update unistyles",
"convert unistyles v2". Covers all API changes including StyleSheet.create,
useStyles removal, theme configuration, variants, withUnistyles, Babel plugin setup,
style spreading fixes, and third-party component wrapping.
disable-model-invocation: false
user-invocable: true
allowed-tools: Read, Grep, Glob, Edit, Write, Bash(npx *)
Unistyles v2 to v3 Migration Skill
You are migrating a React Native codebase from react-native-unistyles v2 to v3. Follow this workflow precisely. v3 is a complete rewrite with C++ core (Nitro Modules), no re-renders, and a Babel plugin that processes StyleSheets at build time.
Prerequisites
- React Native 0.78.0+ with New Architecture **mandatory** (enabled by default from RN 0.83+)
- React 19+ (enforced at runtime by Unistyles)
- `react-native-nitro-modules` (native bridge dependency)
- `react-native-edge-to-edge` (required for Android edge-to-edge insets)
- Expo SDK 53+ (if using Expo; not compatible with Expo Go — requires dev client or prebuild)
- Xcode 16+ (iOS)
Migration Workflow
Follow these steps IN ORDER. Each step must be completed before moving to the next.
Step 1: Install v3 and configure Babel plugin
Install `react-native-unistyles@3` and add the Babel plugin:
// babel.config.js
module.exports = {
plugins: [
['react-native-unistyles/plugin', { root: 'src' }] // your app source root
]
}The `root` option is REQUIRED. It tells the plugin which directory contains your app code. Files outside this directory (except node_modules paths you explicitly configure) won't be processed.
If using React Compiler, the Unistyles plugin MUST come BEFORE React Compiler in the plugins array.
Step 2: Replace UnistylesRegistry with StyleSheet.configure
- import { UnistylesRegistry } from 'react-native-unistyles'
+ import { StyleSheet } from 'react-native-unistyles'
- UnistylesRegistry
- .addThemes({ light: lightTheme, dark: darkTheme })
- .addBreakpoints({ sm: 0, md: 768, lg: 1200 })
- .addConfig({
- adaptiveThemes: true,
- initialTheme: 'dark',
- plugins: [myPlugin],
- experimentalCSSMediaQueries: true,
- windowResizeDebounceTimeMs: 100,
- disableAnimatedInsets: true
- })
+ StyleSheet.configure({
+ themes: { light: lightTheme, dark: darkTheme },
+ breakpoints: { sm: 0, md: 768, lg: 1200 },
+ settings: {
+ adaptiveThemes: true,
+ initialTheme: 'dark'
+ }
+ })**Removed settings:** `plugins`, `experimentalCSSMediaQueries` (now always on), `windowResizeDebounceTimeMs` (no debounce), `disableAnimatedInsets` (insets no longer re-render).
Step 3: Replace all StyleSheet imports and createStyleSheet
Unistyles `StyleSheet` is a full polyfill of React Native's `StyleSheet` — it includes `hairlineWidth`, `compose`, `flatten`, `absoluteFill`, and `absoluteFillObject`. You should replace **all** `import { StyleSheet } from 'react-native'` with `import { StyleSheet } from 'react-native-unistyles'` so you have a single import.
- import { StyleSheet } from 'react-native'
- import { createStyleSheet } from 'react-native-unistyles'
+ import { StyleSheet } from 'react-native-unistyles'
- const stylesheet = createStyleSheet(theme => ({
+ const styles = StyleSheet.create(theme => ({
container: {
backgroundColor: theme.colors.background
}
}))Step 4: Remove all useStyles hooks
- import { useStyles } from 'react-native-unistyles'
const MyComponent = () => {
- const { styles, theme } = useStyles(stylesheet)
return <View style={styles.container} />
}Styles created with `StyleSheet.create` are used directly - no hook needed. The Babel plugin handles reactivity at build time.
Step 5: Replace useInitialTheme with settings.initialTheme
- import { useInitialTheme } from 'react-native-unistyles'
-
- const App = () => {
- useInitialTheme(storage.getString('preferredTheme') ?? 'light')
- return <Stack />
- }
+ // In your configure call:
+ StyleSheet.configure({
+ settings: {
+ initialTheme: () => storage.getString('preferredTheme') ?? 'light'
+ }
+ })`initialTheme` accepts a string or a synchronous function.
Step 6: Replace useStyles() for theme access
For components that used `useStyles()` (without a stylesheet) just to get theme/runtime:
**Option A - withUnistyles (preferred for passing theme-derived props):**
import { withUnistyles } from 'react-native-unistyles'
const UniButton = withUnistyles(Button, (theme, rt) => ({
color: theme.colors.primary,
size: rt.screen.width > 400 ? 'large' : 'small'
}))
// Usage: <UniButton />**Option B - useUnistyles hook (quick migration path):**
import { useUnistyles } from 'react-native-unistyles'
const MyComponent = () => {
const { theme, rt } = useUnistyles()
return <Text style={{ color: theme.colors.primary }}>{rt.screen.width}</Text>
}**WARNING:** `useUnistyles` causes re-renders when theme/runtime changes. Prefer `withUnistyles` or `StyleSheet.create(theme => ...)` for performance.
Step 7: Update variant selection
- const { styles } = useStyles(stylesheet, { size: 'large', color: 'primary' })
+ styles.useVariants({ size: 'large', color: 'primary' })Call `styles.useVariants()` at the top of your component (like a hook). It must be called before accessing styles that use variants.
Step 8: Fix style spreading (CRITICAL)
v3 styles are C++ proxy objects. Spreading breaks the binding.
- <View style={{ ...styles.container, ...styles.extra }} />
+ <View style={[styles.container, styles.extra]} />
- <View style={{ ...styles.container, marginTop: 10 }} />
+ <View style={[styles.container, { marginTop: 10 }]} />NEVER use `{...styles.x}`. ALWAYS use `[styles.x,
Read more
name: unistyles-v2-to-v3-migration description: > Migrate react-native-unistyles from v2 to v3. Triggers on: "migrate unistyles", "upgrade unistyles", "v2 to v3", "unistyles migration", "update unistyles", "convert unistyles v2". Covers all API changes including StyleSheet.create, useStyles removal, theme configuration, variants, withUnistyles, Babel plugin setup, style spreading fixes, and third-party component wrapping. disable-model-invocation: false user-invocable: true allowed-tools: Read, Grep, Glob, Edit, Write, Bash(npx *)
Unistyles v2 to v3 Migration Skill
You are migrating a React Native codebase from react-native-unistyles v2 to v3. Follow this workflow precisely. v3 is a complete rewrite with C++ core (Nitro Modules), no re-renders, and a Babel plugin that processes StyleSheets at build time.
Prerequisites
- React Native 0.78.0+ with New Architecture **mandatory** (enabled by default from RN 0.83+)
- React 19+ (enforced at runtime by Unistyles)
- `react-native-nitro-modules` (native bridge dependency)
- `react-native-edge-to-edge` (required for Android edge-to-edge insets)
- Expo SDK 53+ (if using Expo; not compatible with Expo Go — requires dev client or prebuild)
- Xcode 16+ (iOS)
Migration Workflow
Follow these steps IN ORDER. Each step must be completed before moving to the next.
Step 1: Install v3 and configure Babel plugin
Install `react-native-unistyles@3` and add the Babel plugin:
// babel.config.js
module.exports = {
plugins: [
['react-native-unistyles/plugin', { root: 'src' }] // your app source root
]
}The `root` option is REQUIRED. It tells the plugin which directory contains your app code. Files outside this directory (except node_modules paths you explicitly configure) won't be processed.
If using React Compiler, the Unistyles plugin MUST come BEFORE React Compiler in the plugins array.
Step 2: Replace UnistylesRegistry with StyleSheet.configure
- import { UnistylesRegistry } from 'react-native-unistyles'
+ import { StyleSheet } from 'react-native-unistyles'
- UnistylesRegistry
- .addThemes({ light: lightTheme, dark: darkTheme })
- .addBreakpoints({ sm: 0, md: 768, lg: 1200 })
- .addConfig({
- adaptiveThemes: true,
- initialTheme: 'dark',
- plugins: [myPlugin],
- experimentalCSSMediaQueries: true,
- windowResizeDebounceTimeMs: 100,
- disableAnimatedInsets: true
- })
+ StyleSheet.configure({
+ themes: { light: lightTheme, dark: darkTheme },
+ breakpoints: { sm: 0, md: 768, lg: 1200 },
+ settings: {
+ adaptiveThemes: true,
+ initialTheme: 'dark'
+ }
+ })**Removed settings:** `plugins`, `experimentalCSSMediaQueries` (now always on), `windowResizeDebounceTimeMs` (no debounce), `disableAnimatedInsets` (insets no longer re-render).
Step 3: Replace all StyleSheet imports and createStyleSheet
Unistyles `StyleSheet` is a full polyfill of React Native's `StyleSheet` — it includes `hairlineWidth`, `compose`, `flatten`, `absoluteFill`, and `absoluteFillObject`. You should replace **all** `import { StyleSheet } from 'react-native'` with `import { StyleSheet } from 'react-native-unistyles'` so you have a single import.
- import { StyleSheet } from 'react-native'
- import { createStyleSheet } from 'react-native-unistyles'
+ import { StyleSheet } from 'react-native-unistyles'
- const stylesheet = createStyleSheet(theme => ({
+ const styles = StyleSheet.create(theme => ({
container: {
backgroundColor: theme.colors.background
}
}))Step 4: Remove all useStyles hooks
- import { useStyles } from 'react-native-unistyles'
const MyComponent = () => {
- const { styles, theme } = useStyles(stylesheet)
return <View style={styles.container} />
}Styles created with `StyleSheet.create` are used directly - no hook needed. The Babel plugin handles reactivity at build time.
Step 5: Replace useInitialTheme with settings.initialTheme
- import { useInitialTheme } from 'react-native-unistyles'
-
- const App = () => {
- useInitialTheme(storage.getString('preferredTheme') ?? 'light')
- return <Stack />
- }
+ // In your configure call:
+ StyleSheet.configure({
+ settings: {
+ initialTheme: () => storage.getString('preferredTheme') ?? 'light'
+ }
+ })`initialTheme` accepts a string or a synchronous function.
Step 6: Replace useStyles() for theme access
For components that used `useStyles()` (without a stylesheet) just to get theme/runtime:
**Option A - withUnistyles (preferred for passing theme-derived props):**
import { withUnistyles } from 'react-native-unistyles'
const UniButton = withUnistyles(Button, (theme, rt) => ({
color: theme.colors.primary,
size: rt.screen.width > 400 ? 'large' : 'small'
}))
// Usage: <UniButton />**Option B - useUnistyles hook (quick migration path):**
import { useUnistyles } from 'react-native-unistyles'
const MyComponent = () => {
const { theme, rt } = useUnistyles()
return <Text style={{ color: theme.colors.primary }}>{rt.screen.width}</Text>
}**WARNING:** `useUnistyles` causes re-renders when theme/runtime changes. Prefer `withUnistyles` or `StyleSheet.create(theme => ...)` for performance.
Step 7: Update variant selection
- const { styles } = useStyles(stylesheet, { size: 'large', color: 'primary' })
+ styles.useVariants({ size: 'large', color: 'primary' })Call `styles.useVariants()` at the top of your component (like a hook). It must be called before accessing styles that use variants.
Step 8: Fix style spreading (CRITICAL)
v3 styles are C++ proxy objects. Spreading breaks the binding.
- <View style={{ ...styles.container, ...styles.extra }} />
+ <View style={[styles.container, styles.extra]} />
- <View style={{ ...styles.container, marginTop: 10 }} />
+ <View style={[styles.container, { marginTop: 10 }]} />NEVER use `{...styles.x}`. ALWAYS use `[styles.x,
Repo: jpudysz/react-native-unistyles

