Skip to content
Development
Skill

/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,

From plugin
react-native-unistyles
2.9k2 skills
Install
$ npx -y skills add jpudysz/react-native-unistyles --skill unistyles-v2-to-v3-migration --agent claude-code

How 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.md
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,

Read more
Ships withreact-native-unistyles

Level up your React Native StyleSheet

Get the whole plugin
Stats
2,933
Stars
118
Forks
Active
Maintenance
TypeScript
Language
1mo ago
Last commit
2y ago
Created

Repo: jpudysz/react-native-unistyles