This is the full 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**
Note
Each configuration is optional but enables advanced features, which are explained in the guide [How Unistyles Works?](/v3/start/how-unistyles-works)
### 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
}
```
Note
Unistyles supports any dynamic theme and doesn’t enforce a specific structure. To avoid TypeScript issues, ensure that all themes share the same type.
### 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
}
```
Note
In the Unistyles 3.0 setting both `initialTheme` and `adaptiveThemes` will cause an error. These options are mutually exclusive.
### 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
})
```
Note
Don’t forget to import this config somewhere in your project, for example in `index.ts` file. You **must** call `StyleSheet.configure` **before** any `StyleSheet.create` call.
For expo router users, please refer to the [Expo Router guide](/v3/guides/expo-router).
# 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`.
Note
Learn more about how Unistyles leverages Nitro Modules and React Native Edge to Edge [here](/v3/other/dependencies).
**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']
]
}
}
```
Note
Learn more on how the Babel plugin works [here](/v3/other/babel-plugin).
If you’re using React Compiler, check [this guide](/v3/guides/react-compiler) for more details.
Check extra configuration options [here](/v3/other/babel-plugin#extra-configuration).
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
Note
Learn more on how the Babel plugin works [here](/v3/other/babel-plugin).
### 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
```
Note
The `unistyles.ts` file is where Unistyles is configured. For more details, refer to the [configuration guide](/v3/start/configuration).
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 (
);
}
```
Note
The `unistyles.ts` file is where Unistyles is configured. For more details, refer to the [configuration guide](/v3/start/configuration).
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()
}
```
Note
It’s also possible to update the theme during runtime. Please check `updateTheme` method in the [UnistylesRuntime](/v3/references/unistyles-runtime) guide.
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.
Note
It’s not recommended to use themes with different shapes. Unistyles allows that, but it might cause some TypeScript errors.
### 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'
}
}
})
```
Note
It’s not possible to use `async` functions with `initialTheme` option.
* 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 = () => (