This is the abridged developer documentation for React Native Unistyles 3.0
# Configuration
> How configure Unistyles
To unlock more features and tailor Unistyles to your needs, you can configure it. The Unistyles configuration is divided into three parts: 1. **Themes** 2. **Breakpoints** 3. **Settings** ### Themes (Optional) `Themes` is a JavaScript object where the keys represent unique theme names, and the values are the corresponding theme definitions. For more details, refer to the [theming](/v3/guides/theming) guide. unistyles.ts ```tsx const lightTheme = { colors: { primary: '#ff1ff4', secondary: '#1ff4ff' // any nesting, spreading, arrays, etc. }, // functions, external imports, etc. gap: (v: number) => v * 8 } const otherTheme = { colors: { primary: '#aa12ff', secondary: 'pink' }, gap: (v: number) => v * 8 } const appThemes = { light: lightTheme, other: otherTheme } ``` ### Breakpoints (Optional) `Breakpoints` is a JavaScript object where the keys are unique breakpoint names and the values are the corresponding breakpoint values (numbers). Be sure to register at least one breakpoint with a value of 0, as it’s required to simulate the cascading behavior of CSS media queries. unistyles.ts ```tsx const breakpoints = { xs: 0, // <-- make sure to register one breakpoint with value 0 sm: 300, md: 500, lg: 800, xl: 1200 // use as many breakpoints as you need } ``` ### Settings (Optional) The `Settings` object has been simplified, and in the most recent version, it supports only four properties: * **`adaptiveThemes`** – a boolean that enables or disables adaptive themes [learn more](/v3/guides/theming#adaptive-themes) * **`initialTheme`** – a string or a synchronous function that sets the initial theme * **`CSSVars`** – a boolean that enables or disables web CSS variables (defaults to `true`) [learn more](/v3/references/web-only#css-variables) * **`nativeBreakpointsMode`** - iOS/Android only. User preferred mode for breakpoints. Can be either `points` or `pixels` (defaults to `pixels`) [learn more](/v3/references/breakpoints#pixelpoint-mode-for-native-breakpoints) unistyles.ts ```tsx const settings = { initialTheme: 'light' } // or with a synchronous function const settings = { initialTheme: () => { // get preferred theme from user's preferences/MMKV/SQL/StanJS etc. return storage.getString('preferredTheme') ?? 'light' } } // or with adaptive themes const settings = { adaptiveThemes: true } ``` ### TypeScript Types (Optional) If your repository is using TypeScript, it is highly recommended to override the library types for optimal autocomplete and type safety regarding your themes and breakpoints: unistyles.ts ```tsx type AppThemes = typeof appThemes type AppBreakpoints = typeof breakpoints declare module 'react-native-unistyles' { export interface UnistylesThemes extends AppThemes {} export interface UnistylesBreakpoints extends AppBreakpoints {} } ``` ### Set configuration The final step in the configuration is to set all the options by calling the `StyleSheet.configure` function: unistyles.ts ```tsx import { StyleSheet } from 'react-native-unistyles' StyleSheet.configure({ themes: appThemes, breakpoints, settings }) ``` That’s it! You can now use all the features of Unistyles in your project! ### Full example unistyles.ts ```tsx import { StyleSheet } from 'react-native-unistyles' const lightTheme = { colors: { primary: '#ff1ff4', secondary: '#1ff4ff' }, gap: (v: number) => v * 8 } const otherTheme = { colors: { primary: '#aa12ff', secondary: 'pink' }, gap: (v: number) => v * 8 } const appThemes = { light: lightTheme, other: otherTheme } const breakpoints = { xs: 0, sm: 300, md: 500, lg: 800, xl: 1200 } type AppBreakpoints = typeof breakpoints type AppThemes = typeof appThemes declare module 'react-native-unistyles' { export interface UnistylesThemes extends AppThemes {} export interface UnistylesBreakpoints extends AppBreakpoints {} } StyleSheet.configure({ settings: { initialTheme: 'light', }, breakpoints, themes: appThemes }) ```
# Getting started
> How to get started with Unistyles
We put a lot of effort into making Unistyles as easy to use as possible. You no longer need the `useStyle` hook or wrap your app in provider. Unistyles integrates seamlessly with your existing code, so you can start using it immediately. ### Prerequisites Unistyles 3.0 is tightly integrated with `Fabric` and the latest version of React Native. Therefore, you must use the **New Architecture** and at least **React Native 0.76.0**. Additionally, Unistyles relies on `react-native-nitro-modules` and `react-native-edge-to-edge`. **Table of requirements:** | | Required | Note | | ---------------- | -------- | ------------------------- | | React Native | 0.76+ | | | New Architecture | enabled | no option to opt-out | | Expo SDK | 52+ | (if you use Expo) | | Xcode | 16+ | Required by Nitro Modules | Caution There is a known bug in Xcode 16.2. If you use this version, please follow [this github issue](https://github.com/jpudysz/react-native-unistyles/issues/507#issuecomment-2602963047) Since Unistyles relies on `Fabric`, it cannot run on the `Old Architecture` or older versions of React Native. If you can’t meet these requirements, you can use Unistyles 2.0+, which is compatible with those versions. ### Installation Install Unistyles and its dependencies ```shell yarn add react-native-unistyles@beta yarn add react-native-nitro-modules react-native-edge-to-edge ``` Caution To avoid unexpected behaviors always use a fixed version of `react-native-nitro-modules`. Check compatibility table [here](https://github.com/jpudysz/react-native-unistyles?tab=readme-ov-file#installation). Add babel plugin: babel.config.js ```js module.exports = function (api) { api.cache(true) return { // for bare React Native // presets: ['module:@react-native/babel-preset'], // or for Expo // presets: ['babel-preset-expo'], // other config plugins: [ // other plugins ['react-native-unistyles/plugin'] ] } } ``` Finish installation based on your platform: * Expo ```shell yarn expo prebuild --clean ``` Dev client only Unistyles includes custom native code, which means it does not support **Expo Go.** * React Native ```shell cd ios && pod install ``` * React Native Web Unistyles offers first-class support for React Native Web. To run the project, we recommend following the guidelines provided by [Expo](https://docs.expo.dev/workflow/web/). * Custom Web 🚧 Work in progress, we will share more details soon. * SSR Unistyles offers first-class support for Next.js Server Side Rendering. To run the project, we recommend following the guidelines provided by [Next.JS](https://nextjs.org/docs). ### As easy as React Native StyleSheet Getting started with Unistyles couldn’t be easier. Simply replace React Native’s `StyleSheet` with the `StyleSheet` exported from Unistyles. From that moment, you’ll be using a `StyleSheet` with superpowers 🦸🏼♂️. Example.tsx ```tsx import { StyleSheet } from 'react-native' import { StyleSheet } from 'react-native-unistyles' const MyComponent = () => { return ( Hello world from Unistyles ) } const styles = StyleSheet.create({ container: { backgroundColor: 'red' } }) ``` By replacing `StyleSheet`, you immediately gain several benefits that aren’t available in React Native’s `StyleSheet`: * [Variants](/v3/references/variants) * [Compound variants](/v3/references/compound-variants) * [Dynamic functions](/v3/references/dynamic-functions) * [Media queries](/v3/references/media-queries) * [Horizontal and vertical breakpoints for Native](/v3/references/breakpoints#built-in-breakpoints-landscape-and-portrait) * [Custom web styles](/v3/references/web-styles) * [Web only features](/v3/references/web-only) When you’re ready to customize your styles and unlock additional features you can [configure](/v3/start/configuration) Unistyles.
# How Unistyles works?
> Understanding how Unistyles 3.0 works
To get the most out of Unistyles, it’s important to understand how it works and how it updates your styles. ### 1. StyleSheets A typical app consist of many `StyleSheets`. A `StyleSheet` is a JavaScript object that holds one or many styles. Each style is associated with native view. What’s more important is that each `StyleSheet` is unique, tailored to the needs of the view, or to a shared component.  Your app’s StyleSheets ### 2. Babel plugin: dependencies Unistyles needs to understand your `StyleSheet` dependencies in order to update them only when necessary. This process begins when Babel transforms your app’s code. At this stage, the Unistyles Babel plugin scans your `StyleSheets` and determines the dependencies for each style: ```ts const styles = StyleSheet.create((theme, rt) => ({ // static: no dependencies container: { backgroundColor: 'red', }, // depends on theme and font scale text: { color: theme.colors.text, fontSize: rt.fontScale * 16 }, dynamic: (isOdd: boolean) => ({ // depends on theme color: isOdd ? theme.colors.primary : theme.colors.secondary, }) }) ``` ### 3. Babel plugin: component factory As you already know, Unistyles has no components. This means your native view hierarchy remains exactly the same as in your original code. The Babel plugin processes your components through our component factory to borrow `refs` and bind the `ShadowNode` with `Unistyle`. You might be wondering, what is `Unistyle`? We refer to it as your `StyleSheet` style that have been parsed by the Unistyles compiler, and with the attached `C++` state.  Your styles are transformed into Unistyles ### 4. StyleSheet registry We don’t just extract metadata from your styles. We do the same for your `StyleSheet`. On the C++ side, we know exactly which `StyleSheet` is static, which depends on a `theme`, and which `Unistyles` it contains. At this point, your app’s `StyleSheets` are reconstructed on the C++ side and stored in native C++ `StyleSheets`, which contain the parsed `Unistyles`.  C++ StyleSheets that contains parsed styles (Unistyles) To make this process easier to visualize, imagine that the Unistyles engine is a production line. It takes your raw `StyleSheets`, parses them, and produces their C++ representation with `Unistyles`:  Unistyles workflow ### 5. Reacting to events When you access your `StyleSheet` styles in your component, you’ll get a regular JS object as expected. If your component re-renders, we simply return the same `Unistyle` that’s already parsed and stored in the cache. To visualize the true power of `Unistyles`, imagine that some event occurs, such as: * A theme change triggered by the user clicking a button * A phone color scheme change * A phone orientation change * Accessibility settings being updated * and much more! Unistyles is able to update your styles based on 14 events At this point, the Unistyles algorithm scans the `StyleSheetRegistry` and looks for styles that depend on this event:  Finding affected styles Affected styles are then re-computed to reflect the new state of your app. ### 6. Shadow Tree updates With the list of affected styles, we can now browse the `ShadowRegistry`, where we keep the bindings between `ShadowNode` and `Unistyles`. In other words, we know which `component` relies on which `style`. With all this information, we can translate the update into atomic `ShadowTree` instructions. With Unistyles 2.0 or any other library, we would need to re-render your entire app to reflect the changes:  Regular flow: your app is re-rendered Instead, with all the optimizations and features that Unistyles 3.0 brings, we can target only specific nodes and update your `ShadowTree` directly from C++:  Unistyles 3.0 updates only selected ShadowNodes from C++ With this architecture and the power of selective updates through `ShadowTree`, your components are never re-rendered. *Engineering is the closest thing to magic that exists in the world.* \~Elon Musk
# Introduction
> Welcome to Unistyles!
Beta Unistyles 3.0 is still in beta. We’re waiting for the community feedback before promoting it to the stable.  Unistyles is a cross-platform library that enables you to share up to 100% of your styles across all platforms. It combines the simplicity of `StyleSheet` with the performance of `C++`. **`Unistyles` is a superset of `StyleSheet`** similar to how `TypeScript` is a superset of `JavaScript`. If you’re familiar with styling in React Native, then you already know how to use `Unistyles`. ### Why should you use Unistyles? * Guarantees no re-renders across the entire app (no hooks, no context—just pure JSI bindings) * Doesn’t pollute your native view hierarchy (Unistyles has no component wrappers) * Includes a cross-platform parser written in C++, ensuring consistent output across all platforms * Leverages [Nitro Modules](https://nitro.margelo.com/) under the hood (everything is strongly typed!) * Transforms your `StyleSheets` into enhanced `StyleSheets` with superpowers 🦸🏼♂️ that can access themes, platform-specific values, and more! * Loved by developers worldwide: 1.5M+ downloads and over 1.9K stars on GitHub
# Migration guide
> How to migrate from previous version
The migration process is quite simple, but it can be tedious since you’ll need to remove a lot of the existing code. 1. Follow installation steps from [Getting started](/v3/start/getting-started) guide. 2. Replace your configuration with [new](/v3/start/configuration) one. `UnistylesRegistry` can be easily replaced with `StyleSheet.configure` as it follows the same syntax. `Themes` and `Breakpoints` work exactly the same. For `Settings` we removed 4 out of 6 options: ```tsx import { UnistylesRegistry } from 'react-native-unistyles' import { StyleSheet } from 'react-native-unistyles' UnistylesRegistry.addConfig({ adaptiveThemes: false, initialTheme: 'dark', plugins: [...], experimentalCSSMediaQueries: true, windowResizeDebounceTimeMs: 100, disableAnimatedInsets: true }) StyleSheet.configure({ settings: { adaptiveThemes: false, // works exactly the same like in 2.0 initialTheme: 'dark', // works exactly the same like in 2.0 // plugins are removed, instead transform your styles with static functions // experimentalCSSMediaQueries: these options is also removed, and enabled by default with custom parser // windowResizeDebounceTimeMs: removed, there is no debouncing anymore. Styles are updated with CSS media queries // disableAnimatedInsets: removed, insets won't re-render your views } }) ``` 3. Import `StyleSheet` from `react-native-unistyles`: ```tsx import { createStyleSheet, useStyles } from 'react-native-unistyles' import { StyleSheet } from 'react-native-unistyles' ``` 4. Replace `createStyleSheet` with `StyleSheet.create`: ```tsx const stylesheet = createStyleSheet(theme => ({ const stylesheet = StyleSheet.create(theme => ({ ``` 5. Remove all occurrences of `useStyles` hook: ```tsx const { styles } = useStyles(stylesheet) ``` 6. Rename your `stylesheet` to `styles`: ```tsx const stylesheet = StyleSheet.create(theme => ({ const styles = StyleSheet.create(theme => ({ ``` 7. If you used `useInitialTheme`, remove it and set initial theme in `StyleSheet.configure`: ```tsx import { StyleSheet } from 'react-native-unistyles' StyleSheet.configure({ themes, breakpoints, settings: { initialTheme: () => { // get preferred theme from user's preferences/MMKV/SQL/StanJS etc. // must be synchronous return storage.getString('preferredTheme') ?? 'light' } } }) ``` 8. If you need to access your `theme` in component, refactor it to use `withUnistyles`: ```tsx import { Button } from 'react-native' import { useStyles } from 'react-native-unistyles' import { withUnistyles } from 'react-native-unistyles' const UniButton = withUnistyles(Button, theme => ({ color: theme.colors.primary })) const MyButton = () => { return } const MyButton = () => { const { theme } = useStyles(stylesheet) return return } ``` 9. If you want to speed up the migration process, but keep your views re-rendered, use [useUnistyles](/v3/references/use-unistyles) hook: ```tsx import { Button } from 'react-native' import { useUnistyles } from 'react-native-unistyles' const MyText = () => { const { theme } = useUnistyles() return ( ) } ``` 10. If you need to access `breakpoint` to show/hide your components use `Display` and `Hide` components instead: ```tsx import { Text } from 'react-native' import { Display, Hide, mq } from 'react-native-unistyles' const MyText = () => { return ( This text is visible on small devicesThis text is hidden on big devices ) } ``` 11. If you used `UnistylesProvider`, remove it as it’s not available anymore: ```tsx import { UnistylesProvider } from 'react-native-unistyles' ``` 12. If you want to move your component based on keyboard position, use `ime` inset: ```tsx const style = StyleSheet.create({ container: { paddingBottom: rt.insets.bottom // bottom is no longer dynamic paddingBottom: rt.insets.ime } }) ``` 13. Some `UnistylesRuntime` methods have been renamed. Follow TypeScript types to use new names. 14. Some `UnistylesRuntime` methods have been removed: ```tsx UnistylesRuntime.addPlugin(plugin) // Unistyles has no plugins anymore UnistylesRuntime.removePlugin(plugin) // Unistyles has no plugins anymore UnistylesRuntime.statusBar.setColor(color) // removed due to Android 15 deprecation UnistylesRuntime.navigationBar.setColor(color) // removed due to Android 15 deprecation ``` 15. `UnistylesRuntime` methods that accepted `color` and `alpha` have been changed to accept `color` only. Each method supports **any** color that is respected by React Native: ```tsx UnistylesRuntime.setRootViewBackgroundColor(color, alpha) // no need for separate alpha UnistylesRuntime.setRootViewBackgroundColor(color) // accepts any color ``` 16. `hairlineWidth` has been moved from `UnistylesRuntime` to `StyleSheet`. Use `StyleSheet.hairlineWidth` instead: ```tsx UnistylesRuntime.hairlineWidth // no longer available StyleSheet.hairlineWidth // matches StyleSheet API ``` 17. If your app used variants, move config to `styles.useVariants` instead: ```tsx import { useStyles } from 'react-native-unistyles' import { StyleSheet } from 'react-native-unistyles' const MyComponent = () => { const { styles } = useStyles(stylesheet, { variant1: 'primary', variant2: 'secondary' }) styles.useVariants({ variant1: 'primary', variant2: 'secondary' }) return } ``` 18. `Style is not bound!` error or `Unistyles: we detected style object with N unistyles styles. (...)` warning If you encountered this warning or error, it means that you’re spreading your styles. This is not possible in Unistyles 3.0 anymore as spreading will remove `C++` state: ```tsx // not ok const styles = {...style1, ...style2} // not ok ``` Instead, use array syntax provided by React Native: ```tsx // ok ``` By using array syntax, we know **the order of merging** that is necessary to resolve styles correctly. Learn more about [merging styles](/v3/guides/merging-styles).
# New features
> Whats new in Unistyles 3.0?
Unistyles comes packed with many exciting new features. If you’re upgrading from Unistyles 2.0, here’s a quick summary of what’s new: 1. No re-renders Unistyles is primarily written in `C++` with a thin `JS` layer for both iOS and Android. The key feature of this version is that it doesn’t trigger re-renders—there are no hooks, no context, just pure `JSI` bindings managing your `StyleSheet` styles. Unistyles is integrated with Fabric and the Shadow Tree, directly updating your views from C++. 2. Selective updates Unistyles includes a special algorithm that only recalculates styles dependent on the change. For example, if the app user switches to a dark color scheme, Unistyles will only re-calculate and update the styles affected by the change. 3. Compound variants Unistyles extends the `variants` feature by allowing you to define `compound variants`. These are additional styles that are applied when certain conditions are met. For instance, you can define a compound variant to change the text color when the text is bold and uses the primary color. 4. Scoped themes You can now limit the scope of your theme to specific components, allowing different themes for different screens. For example, you can enforce a dark theme only on the login screen. 5. Custom web parser We’ve moved away from relying on `react-native-web` and implemented a custom parser that translates your styles into CSS classes. This parser is tailored to Unistyles syntax, including `mq`, `breakpoints`, `variants`, and `compoundVariants`. Importantly, it remains backwards compatible with React Native Web! 6. Custom CSS classes binded to styles For cross-platform apps, styling components like `tr` or `td` — which aren’t available in React Native can be challenging. Unistyles 3.0 allows you to define custom CSS classes that bind directly to your styles, so you can apply extra CSS styles as needed. This also means that you can use `Tailwind` implementation for your web app! 7. Pseudo-classes Unistyles 3.0 now supports all available CSS pseudo-classes! Easily add hover, focus, and active effects to your components. 8. Custom web styles If you need to style a component with web-only properties, it’s now possible. Add any CSS web property directly to your `StyleSheet` styles, such as web-based animations. 9. 1:1 parity with React Native StyleSheet You can now mix Unistyles with React Native StyleSheet and enable superpowers 🦸🏼♂️ on selected screens without additional configuration. If Unistyles doesn’t suit your needs, you can easily revert to React Native StyleSheet. 10. Support for any color format Unistyles now supports any color format that React Native can handle, including HEX, RGB, HSL, and more. We’ll also auto-convert your colors in any call to UnistylesRuntime. And much more! Unistyles 3.0 is loaded with new features, so we encourage you to explore the docs and dive into the library!
# When to use Unistyles 3.0?
> Learn more when should you consider using Unistyles 3.0
This guide will explain when you should consider using Unistyles and when it’s not the best option. ### When should you use Unistyles? Unistyles is recommended for projects that: * leverage the New Architecture and care about performance and memory usage * use two or more themes (we support an unlimited number of themes and [adaptive themes](/v3/guides/theming#adaptive-themes)) * require rendering on the web (we [auto-generate](/v3/references/web-styles) CSS classes) * want to use [variants](/v3/references/variants) and [compound variants](/v3/references/compound-variants) * want to use pseudo-classes and custom web styles ([learn more](/v3/references/web-only)) * feel confident with the styling patterns introduced by React Native (Unistyles follows the same approach) * don’t want to pollute your native view hierarchy ### When is Unistyles not the best option? * You’re looking for a component library (Unistyles has no components, instead we encourage you to build your own design system specifically tailored to your project) * You use Tailwind on the web, as Unistyles has no native bindings to process `classNames` on native side. Instead, we recommend using [NativeWind](https://www.nativewind.dev/) * You’re building a super simple app that doesn’t require theme changes or any advanced features. In this case, stick with React Native’s `StyleSheet` and consider updating to Unistyles 3.0 when it will be more efficient ### When you can’t use Unistyles 3.0? * In Expo Go apps, as Unistyles is not (yet) selected by the Expo team * In apps that can’t update to the New Architecture. Instead, consider using [Unistyles 2.0](https://v2.unistyl.es/start/introduction/) ### Other alternatives To find other alternatives, please check the latest [State of React Native survey](https://stateofreactnative.com/).
# Avoiding keyboard
> Learn how to avoid keyboard with Unistyles
Unistyles 3.0 introduces a new `inset` called `ime`, which is automatically animated when the keyboard appears or disappears. Using this inset in your style will automatically register it for future updates. Unistyles dynamically re-calculates your styles based on their dependencies. To learn more about how Unistyles re-calculates your styles, please refer to the [guide](/v3/start/how-unistyles-works). ### Usage ```tsx import { TextInput, View } from 'react-native' import { StyleSheet } from 'react-native-unistyles' const KeyboardAvoidingView = () => { return ( ) } const styles = StyleSheet.create((theme, rt) => ({ container: { flex: 1, alignItems: 'center', justifyContent: 'flex-end', backgroundColor: theme.colors.backgroundColor, paddingHorizontal: theme.gap(2), paddingTop: rt.insets.top, transform: [ { translateY: rt.insets.ime * -1 } ] }, input: { width: '100%', } })) ``` In this example, the `container` will automatically adjust to avoid the keyboard, ensuring the `input` remains visible at all times.
# Custom Web
> Learn how to use Unistyles 3.0 without React Native Web
It’s possible to render Unistyles without `react-native-web` dependency. 🚧 Work is progress. Guide will be released soon.
# Expo Router
> Integrate Expo Router with Unistyles
[Expo Router](https://docs.expo.dev/router/introduction/) is a popular routing library from Expo that is built on top of React Navigation. When using Unistyles with Expo Router, it’s necessary to configure it properly. ### Modify main entry Expo Router resolves routes differently that expected. Also, Unistyles 3.0 is parsing your `StyleSheets` as soon as you import file containing it. This combination may cause some issues. To prevent that you need to modify your main entry file: package.json ```json { "main": "expo-router/entry" "main": "index.ts" } ``` Then, create `index.ts` file with following content: index.ts ```js import 'expo-router/entry' import './unistyles' // <-- file that initializes Unistyles ``` With this setup, we will ensure that Unistyles is initialized before any other component. ### Expo Router Web - Static rendering Caution This is the default option in Expo SDK 52. You can check if you are using static rendering in `app.json`: app.json ```json { "expo": { "web": { "bundler": "metro", "output": "static" } } } ``` For Expo static rendering, every page will be resolved with the Root HTML file. Unfortunately, this file is hidden, and you need to create it manually. Please follow the [Expo guide](https://docs.expo.dev/router/reference/static-rendering/#root-html) and add a `+html.tsx` file. In this file, initialize Unistyles by importing the config file: +html.tsx ```tsx import React from 'react' import { ScrollViewStyleReset } from 'expo-router/html' import { type PropsWithChildren } from 'react' import '../unistyles' // <-- file that initializes Unistyles export default function Root({ children }: PropsWithChildren) { ... } ``` This ensures that Unistyles is initialized whenever Expo Router renders the next static page.
# Merging styles
> Learn about how to merge styles with Unistyles 3.0
While using Unistyles, it’s crucial to understand how styles need to be merged and why it is so important. ### Introduction In the early versions of Unistyles 3.0, we tried to solve this issue with a Babel plugin. However, it was too complex to maintain various edge cases (especially with `Pressable`), and developers frequently encountered many `Unistyles: Style is not bound!` errors. With the new approach, we shift the responsibility of merging styles to the user. In other words, the Babel plugin will no longer convert your style tags from objects to arrays. ### How to merge multiple styles Unistyles doesn’t provide any extra API for merging styles. Instead, we encourage you to use the `[]` syntax supported by React Native components. ```tsx ``` If Unistyles detects that you’ve used the spread operator and the styles have no attached C++ state, it will: * Restore the state on the C++ side * Merge styles in an unpredictable order (as we lose order information) * Warn you in `__DEV__` mode about this Example error Unistyles: We detected a style object with 2 Unistyles styles. This might cause no updates or unpredictable behavior. Please check the `style` prop for `View` and use array syntax instead of object syntax. When you see this warning, your component will render correctly, but any new event that re-computes your styles could: * Output incorrect styles due to the unknown order of merging * Not update at all if during the merging process, you altered props that were previously listening for changes It’s critical to ship Unistyles 3.0 apps without this warning, as it can cause unexpected behavior. ### Reanimated By default `Animated` components will flatten your styles array. This means that you can only pass **single** unistyle to `Animated` components. If you want to get rid of this warning, for `react-native-reanimated` 3.x please follow [this thread](https://github.com/jpudysz/react-native-unistyles/issues/512) to apply a patch. Patch is not necessary from `react-native-reanimated` 4.0.0-beta.3 as it was merged to the main branch. ### Spreading a single Unistyle Another problematic case is spreading a single Unistyle and merging it, e.g., with inline styles: ```tsx ``` Although we can restore the C++ state for `styles.container`, we cannot identify that `backgroundColor: red` should override the `backgroundColor` used in `styles.container`. The order of merging will be preserved until the first re-computation of styles. Also, keep in mind that restoring the C++ state takes unnecessary extra time, so it’s better to avoid it. ### Summary * Use the `[]` syntax to merge styles * Avoid spreading Unistyles * Avoid merging your styles with the spread operator * Unistyles will warn you about this in `__DEV__` mode With this new approach, you’re in control of merging your styles.
# React Compiler
> Integrate React Compiler with Unistyles
React Compiler is a build-time tool that automatically optimizes your React app. To integrate Unistyles with React Compiler, proper configuration is essential. ## With Expo For Expo projects, simply follow the [official Expo guide](https://docs.expo.dev/guides/react-compiler/). No additional configuration changes are necessary! ## With Bare React Native For bare React Native projects, refer to the [official React guide](https://react.dev/learn/react-compiler#usage-with-babel) with one key adjustment: Ensure that the React Compiler runs *after* the Unistyles Babel plugin. Failure to do so may result in errors because Unistyles needs to process `Variants` before the React Compiler does. You can read more about the Babel plugin [here](/v3/other/babel-plugin). Here’s a sample configuration for your `babel.config.js`: babel.config.js ```js module.exports = function () { return { plugins: [ ['react-native-unistyles/plugin'], // Must run before react-compiler 'babel-plugin-react-compiler', // Add other plugins here ] } } ```
# SSR
> Learn about SSR with Unistyles 3.0
Unistyles 3.0 is fully compatible with Next.js Server Side Rendering (SSR). We’re supporting both client and server components. ### Usage * App router To use server-side rendered styles, create following **client side** component: Style.tsx ```tsx 'use client' import { PropsWithChildren, useRef } from 'react' import { useServerUnistyles } from 'react-native-unistyles/server' import { useServerInsertedHTML } from 'next/navigation' import './unistyles' export const Style = ({ children }: PropsWithChildren) => { const isServerInserted = useRef(false) const unistyles = useServerUnistyles() useServerInsertedHTML(() => { if (isServerInserted.current) { return null } isServerInserted.current = true return unistyles }) return <>{children}> } ``` With the component in place, make sure it wraps your body’s children: layout.tsx ```tsx import '../unistyles' import { Style } from '../Style' export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( ); } ``` With this setup, we will ensure that Unistyles is initialized correctly and injects CSS on the server side. ### Config (Optional) `useServerUnistyles` accepts an optional config object: * **`includeRNWStyles`** – a boolean that enables or disables injecting React Native Web default CSS styles. Defaults to `true`. * Pages router To use server-side rendered styles, add the following code to your codebase: \_document.tsx ```tsx import { getServerUnistyles, resetServerUnistyles } from 'react-native-unistyles/server' export default class Document extends NextDocument { static async getInitialProps({ renderPage }: DocumentContext) { const page = await renderPage() const styles = getServerUnistyles() resetServerUnistyles() return { ...page, styles } } ``` And add the following use effect to your `_app.tsx` \_app.tsx ```tsx import { hydrateServerUnistyles } from 'react-native-unistyles/server' {/* JSX of your component */} useEffect(() => { hydrateServerUnistyles() }, []) ``` ### Config (Optional) `getServerUnistyles` accepts an optional config object: * **`includeRNWStyles`** – a boolean that enables or disables injecting React Native Web default CSS styles. Defaults to `true`. ## Troubleshooting ### Hydration error If you’re not using adaptive themes, you might encounter hydration error on your root html element. This is because unistyles is adding a className to it based on the current theme. To fix this simply add `suppressHydrationWarning` to your root html element. layout.tsx ```tsx ``` Or you can directly add the className to your root html element. layout.tsx ```tsx ```
# Theming
> Best practices for theming in Unistyles
Theming in `Unistyles` differs from other libraries as it doesn’t impose any specific syntax. **Any JavaScript object can be a Unistyles theme**. There is also no limit to the number of themes. You can even register dozens of them eg. when you needs to support some premium ones. Theming is optional. If you dont’t register themes with [StyleSheet.configure](/v3/start/configuration#themes-optional) the library will use an empty object by default. ### Create a theme You can organize your themes however you want: ```tsx const myTheme = { // any keys colors: { // your colors }, components: { // any number of nesting button: { deepKey: {} } }, utils: { // you can even use functions here hexToRGBA: () => {} }, // or compute your themes with functions and spread operators ...premiumFeatures, ...getMyColors() } ``` If you use TypeScript you need to override the library’s type: ```tsx type AppThemes = { name: typeof myTheme } declare module 'react-native-unistyles' { export interface UnistylesThemes extends AppThemes {} } ``` Finally, to register the theme, you need to call `StyleSheet.configure`: ```tsx import { StyleSheet } from 'react-native-unistyles' import { myTheme } from './themes' StyleSheet.configure({ themes: { name: myTheme, // you can add more themes here } }) ``` Where `name` is the unique name of your theme. ### Select theme If you’ve registered more than one theme, Unistyles won’t know which one is the initial one. At this point, you have 3 options: * If you know the initial theme upfront, select it with `settings` from [StyleSheet.configure](/v3/start/configuration#settings-optional) ```tsx StyleSheet.configure({ settings: { initialTheme: 'premium' } }) ``` * If you need to resolve the user-selected theme during runtime, use a synchronous function: ```tsx StyleSheet.configure({ settings: { initialTheme: () => { // get preferred theme from user's preferences/MMKV/SQL/StanJS etc. return storage.getString('preferredTheme') ?? 'light' } } }) ``` * Use adaptive themes, which are described below ### Get the current theme To get the current theme you can access it in the `StyleSheet.create` function: ```tsx const styles = StyleSheet.create(theme => ({ ... })) ``` Other, discouraged way is to access it in the hook `useUnistyles`: ```tsx import { useUnistyles } from 'react-native-unistyles' const MyComponent = () => { const { theme } = useUnistyles() return ( My theme is {theme.colors.primary} ) } ``` Caution `useUnistyles` is not recommended as it will re-render your component on every change of the theme. Lear more about [useUnistyles](/v3/references/use-unistyles) ### Get the current theme name To get the current theme name, import `UnistylesRuntime`: ```tsx import { UnistylesRuntime } from 'react-native-unistyles' // access the current theme name in your component export const UserTheme = () => ( Selected theme is {UnistylesRuntime.themeName} ) ``` ### Adaptive themes Adaptive themes allow Unistyles to automatically manage the selection of your themes based on device color scheme settings. To enable this, you need to meet two conditions: * register two themes with reserved names `light` and `dark`: ```tsx StyleSheet.configure({ themes: { light: lightTheme, dark: darkTheme, // you may have more themes } }) ``` * Explicitly enable `adaptiveThemes`: ```tsx StyleSheet.configure({ themes: { light: lightTheme, dark: darkTheme }, settings: { adaptiveThemes: true } }) ``` Caution Setting initial theme and enabling adaptive themes at the same time will throw an error as this options are mutually exclusive. ### Toggle adaptive themes during runtime To toggle adaptive theme support at any point, use `UnistylesRuntime`: ```tsx import { UnistylesRuntime } from 'react-native-unistyles' // toggle support for adaptive themes at any point export const ToggleAdaptiveThemes = () => (