Styling
One component, three styling variants. Axiom adapts to the tool your project already uses.
Axiom doesn’t come with its own styling syntax. Each component exists in several variants, and your project uses the one that matches its stack.
Your components, your styling.
| Variant | Tool | Dependency |
|---|---|---|
stylesheet | React Native StyleSheet | none |
unistyles | react-native-unistyles | react-native-unistyles |
tailwind | NativeWind or Uniwind | nativewind or uniwind |
NativeWind and Uniwind share the tailwind variant. Component classes are identical; only the setup differs (config, Babel or Metro plugin, supported Tailwind versions), and init handles it.
Rollout
stylesheet ships first for every component. unistyles follows, then
tailwind once the behavior / style split is proven on the first two.
Choosing a variant
stylesheetif you don’t use a styling library, or want zero extra dependencies. It needs no global provider.unistylesif your project already uses Unistyles.tailwindif your project uses NativeWind or Uniwind.
You choose once, at npx axiom init. The choice is stored in axiom.json and every add copies that variant.
Behavior and style are separate
What makes a component useful on mobile (state, gestures, animation, accessibility, touch targets) doesn’t depend on the styling tool. It is written once and shared by every variant.
Behavior (shared) Style (per variant)
───────────────── ───────────────────
core/ Tappable, Overlay… stylesheet/ StyleSheet.create + useTheme
hooks/ useSwitch, useSlider… unistyles/ StyleSheet.create((theme) => …)
tailwind/ className + variants- Non-trivial logic lives in
core/,hooks/or a hook next to the component. - A variant file only renders and styles. It never reimplements a behavior.
- Components without logic (Badge, Separator…) are just one file per variant.
- Every variant is written by hand, so it stays readable and easy to change. Nothing is generated from a shared source.
You only receive the shared behavior and the file for your variant, side by side:
components/ui/
├── use-switch.ts # shared behavior
└── switch.tsx # your variantSee Where files go.
The theme in each variant
The theme contracts (Tokens, ThemeColors, Components) and the default values don’t depend on the styling tool. Each variant translates them into its own form:
// `light` and `dark` objects, picked by a hook based on the system color scheme.
import { useColorScheme } from "react-native";
export const light = { tokens, colors: lightColors };
export const dark = { tokens, colors: darkColors };
export function useTheme() {
return useColorScheme() === "dark" ? dark : light;
}// Themes registered once, then switched automatically by Unistyles.
import { StyleSheet } from "react-native-unistyles";
StyleSheet.configure({
themes: { light, dark },
settings: { adaptiveThemes: true },
});/* Tokens exposed as CSS variables, then referenced in the Tailwind config. */
:root {
--color-background: hsla(0, 0%, 100%, 1);
--color-content: hsla(0, 0%, 4%, 1);
}
.dark {
--color-background: hsla(0, 0%, 4%, 1);
--color-content: hsla(0, 0%, 98%, 1);
}See Foundations for the contracts.
How the tools differ
The variants don’t only differ in syntax:
stylesheet | unistyles | tailwind | |
|---|---|---|---|
| Theme access | useTheme() | built in | variables / classes |
Variants (size, variant) | style objects picked by hand | native variants | tailwind-variants or cva |
| Dark mode | useColorScheme | adaptive themes | dark: prefix |
| Animated styles (Reanimated) | animated style | animated style | animated style alongside className |
Same contract everywhere
For a given component, every variant has:
- the same props: names, types and defaults;
- the same behavior and accessibility;
- the same look with the default theme.
The one exception is each tool’s natural extension: every variant accepts style, and tailwind also accepts className.
Parity is checked in the demo app and in CI.
Switching later
Changing styling in axiom.json only affects components you add afterwards. Files already copied stay as they are, because they belong to your project. To move an existing component to another variant, add it again and confirm the overwrite, or port your version by hand.