The quickest dark mode is the dark: variant: bg-white dark:bg-slate-900 switches with the device's appearance. It doubles every color class, though. BookNest instead names its colors after their roles and stores the values in CSS variables, which one media query redefines for dark mode:
:root {
--brand: 21 101 192; /* #1565c0 */
--surface: 255 255 255;
--page: 236 239 241; /* #eceff1 */
--ink: 33 33 33;
}
@media (prefers-color-scheme: dark) {
:root {
--brand: 144 202 249; /* #90caf9 */
--surface: 27 42 65;
--page: 11 19 32;
--ink: 227 242 253;
}
} colors: {
brand: 'rgb(var(--brand) / <alpha-value>)',
surface: 'rgb(var(--surface) / <alpha-value>)',
page: 'rgb(var(--page) / <alpha-value>)',
ink: 'rgb(var(--ink) / <alpha-value>)',
},Components now say bg-surface text-ink and never mention dark mode; <alpha-value> keeps text-ink/60 working. Two settings make the switch reach the app. Expo 6,418 apps follow the system appearance only with "userInterfaceStyle": "automatic" in app.json (BookNest had "light"), and navigation chrome is not NativeWind's: the root layout passes DarkTheme or DefaultTheme, which Expo Router 57 6,418 exports, to its ThemeProvider. To let users override the system, NativeWind's useColorScheme() returns setColorScheme():
const { colorScheme, setColorScheme } = useColorScheme();
{choices.map((c) => (
<Pressable key={c} onPress={() => setColorScheme(c)}Tapping Dark, then System, then switching the emulator's night mode on and off (adb -s emulator-5554 shell cmd uimode night yes) logged from the root layout:
LOG color scheme: dark LOG color scheme: light LOG color scheme: dark LOG color scheme: light
For themes chosen at run time (a seasonal palette, a user's accent color), vars({ '--brand': '46 125 50' }) from nativewind returns a style that redefines the variables for one subtree.