Dark Mode
Set up dark mode in your React Native app with NativeWind or Uniwind.
How It Works#
AniUI uses CSS custom properties with a .dark class. NativeWind automatically applies the dark class based on the device's color scheme. All AniUI components respond to dark mode without any extra configuration.
Expo Setup#
1. Configure app.json#
Set userInterfaceStyle to "automatic" to follow the system setting:
{
"expo": {
"userInterfaceStyle": "automatic"
}
}2. Import global CSS#
Make sure your root layout imports the global stylesheet:
import "../global.css";
export default function RootLayout() {
// ...
}That's it. NativeWind detects the system color scheme and applies the .dark class automatically. All CSS variables switch between their light and dark values.
Manual Toggle#
To let users switch themes manually, use NativeWind's useColorScheme hook:
import { Pressable, Text } from "react-native";
import { useColorScheme } from "nativewind";
export function ThemeToggle() {
const { colorScheme, toggleColorScheme } = useColorScheme();
return (
<Pressable
onPress={toggleColorScheme}
className="rounded-md bg-secondary px-4 py-2"
>
<Text className="text-secondary-foreground">
{colorScheme === "dark" ? "Light Mode" : "Dark Mode"}
</Text>
</Pressable>
);
}Uniwind#
Uniwind uses Uniwind.setTheme() for programmatic theme switching. Dark mode values are defined in global.css using a @media (prefers-color-scheme: dark) block.
1. global.css setup#
Make sure your CSS has @import "uniwind" and uses @layer theme with @variant light/dark:
@import "tailwindcss";
@import "uniwind";
@theme {
--radius: 0.5rem;
}
@layer theme {
:root {
@variant light {
--color-background: hsl(0 0% 100%);
--color-foreground: hsl(240 10% 3.9%);
--color-primary: hsl(240 5.9% 10%);
/* ... light values */
}
@variant dark {
--color-background: hsl(240 10% 3.9%);
--color-foreground: hsl(0 0% 98%);
--color-primary: hsl(0 0% 98%);
/* ... dark values */
}
}
}2. Toggle theme#
import { Pressable, Text } from "react-native";
import { Uniwind, useUniwind } from "uniwind";
export function ThemeToggle() {
const { theme } = useUniwind();
return (
<Pressable
onPress={() => {
const next = Uniwind.currentTheme === "light" ? "dark" : "light";
Uniwind.setTheme(next);
}}
className="rounded-md bg-secondary px-4 py-2"
>
<Text className="text-secondary-foreground">
{theme === "dark" ? "Light Mode" : "Dark Mode"}
</Text>
</Pressable>
);
}Uniwind.setTheme() automatically calls Appearance.setColorScheme() internally, so native components (Alert, Modal, etc.) also adapt. Use Uniwind.setTheme("system") to re-enable automatic system theme following.
Bare React Native#
For non-Expo projects, NativeWind uses React Native's built-in Appearance API. No extra setup is needed — just ensure your NativeWind config is correct and global.css is loaded.
Using Dark Mode in Components#
AniUI components use semantic color tokens that automatically adapt. If you need conditional styling, use NativeWind's dark: prefix:
<View className="bg-white dark:bg-gray-900">
<Text className="text-black dark:text-white">
Adapts to color scheme
</Text>
</View>
{/* But prefer semantic tokens — they adapt automatically: */}
<View className="bg-background">
<Text className="text-foreground">
Always correct
</Text>
</View>