StyleSheet (plain RN)
Set up StyleSheet (plain RN) for UI in an Expo app with ReadyNative: no style engine, tokens + StyleSheet.create · Expo Go OK
Expo Go: yes
Runs in Expo Go; no dev build needed for this module.
The "no framework" stack: every primitive in @/components/ui is plain React Native styled with StyleSheet.create from src/theme/tokens.ts. Pick it when you don't want a style engine at all - nothing to compile, no className, no dependency beyond core. It's also the clearest read of the contract: src/components/ui/ (src/ui/stylesheet/ before setup) is the reference implementation. Expo Go works.
Setup
bun run setup --ui stylesheetThat's it. Setup writes a plain babel.config.js and metro.config.js (Expo defaults plus the .wasm asset extension), every primitive under src/components/ui/, registers ThemeProvider (order 50), and adds src/components/ui/jest-setup.ts, which stubs @expo/ui native views under jest. Edit src/theme/tokens.ts and the next render picks it up - there's no generate step.
Usage
Screens use the primitives:
import { Card, Screen, Text } from "@/components/ui";
<Screen scroll>
<Card p={4}>
<Text variant="title">Today</Text>
</Card>
</Screen>;Your own components use useStyles - StyleSheet.create bound to the current theme, memoised per mode. Declare the factory at module scope:
import { useStyles, useTheme } from "@/components/ui";
import type { Theme } from "@/components/ui";
const panelStyles = (t: Theme) => ({
root: { backgroundColor: t.colors.card, borderRadius: t.radius.md, padding: t.space[4] },
});
export function Panel() {
const styles = useStyles(panelStyles);
const { colors } = useTheme(); // { mode, colors, space, radius } for inline colours
return <View style={styles.root} />;
}Styles that never read the theme can use StyleSheet.create directly.
To add a primitive to the kit: add its prop type to src/components/ui/types.ts, create src/components/ui/<name>.tsx, and export it from src/components/ui/index.ts.
Gotchas
@expo/uiuniversal components (Host,Switch) are bundled in Expo Go on SDK 57.- A mode change re-renders the context and every primitive rebuilds its styles - there's no engine to notify.
ForcedModeoverrides the context for a subtree. Switchis a native SwiftUI / Compose control insideHost, measured natively, so it can lay out one frame after its siblings. Swap in react-native'sSwitchinswitch.tsxif that bothers you - the label row is already there.- Text variants approximate NativeWind 5's
rnr-textscale (title= h3,heading= h4,subtitle= lead,caption= muted,label= small);codeisfontFamily: "monospace"(Menlo on iOS). - Web is best-effort:
@expo/ui's webSwitchis a styled checkbox from react-native-web.
Remove it
Every app needs a ui option, so there is no none to fall back to - you switch instead. While modules/ exists (a tree set up with --keep-modules), one call does it:
bun run setup --ui nativewind4 --yes --keep-modulesA finalized tree can't switch: clone a fresh copy of your tier repo, run setup there with the new option and port your code across - see Can I change a module after setup?.
Reference
Everything below is generated from modules/ui/stylesheet/module.json - the same file bun run setup reads, so it is what actually lands in your repo.
Install
bun run setup --ui stylesheetModule id: ui/stylesheet.
Providers
Rendered in src/providers.tsx (lower order = outermost):
| Order | Provider | From |
|---|---|---|
| 50 | ThemeProvider as UiThemeProvider | @/ui |
After setup
- Run
bun run start -- -conce so Metro drops the NativeWind transform cache.
Files
24 files copied to the project root
babel.config.jsmetro.config.jssrc/ui/stylesheet/box.tsxsrc/ui/stylesheet/button.tsxsrc/ui/stylesheet/card.tsxsrc/ui/stylesheet/divider.tsxsrc/ui/stylesheet/empty-state.tsxsrc/ui/stylesheet/error-state.tsxsrc/ui/stylesheet/icon.tsxsrc/ui/stylesheet/index.tssrc/ui/stylesheet/input.tsxsrc/ui/stylesheet/jest-setup.tssrc/ui/stylesheet/list.tsxsrc/ui/stylesheet/loading.tsxsrc/ui/stylesheet/pressable.tsxsrc/ui/stylesheet/row.tsxsrc/ui/stylesheet/screen.tsxsrc/ui/stylesheet/sheet.tsxsrc/ui/stylesheet/skeleton.tsxsrc/ui/stylesheet/switch.tsxsrc/ui/stylesheet/text.tsxsrc/ui/stylesheet/theme-provider.tsxsrc/ui/stylesheet/toast.tsxsrc/ui/stylesheet/use-styles.ts