Customization
Ways to customize the theme and the components
Customization
rn-neo is built to be customized. You can change colors, tweak spacing and radius
scales, swap fonts, toggle shadows and borders globally — or override any of it at
the component level on the fly.
Customization works through two props on NeoProvider: theme and config.
<NeoProvider theme={myTheme} config={myConfig}>
<App />
</NeoProvider>Theme vs Config
These two props have different responsibilities:
themecontrols the visual identity — colors, dark mode flag, and global defaults for border, shadow, radius, and animation behavior.configcontrols the design system scale — the actual pixel values behind every token (sm,md,lg, etc.) for spacing, radius, border size, shadow size, and font sizes. It also maps font weight names to font family strings.
Both are optional and support partial overrides — you only need to provide what you want to change. Everything else falls back to the built-in defaults.
Built-in Themes
Two themes ship with rn-neo:
import { DefaultLightTheme, DefaultDarkTheme } from 'rn-neo';DefaultLightTheme is used automatically if you don't pass a theme prop at all.
To use the dark theme, pass it explicitly:
<NeoProvider theme={DefaultDarkTheme}>
<App />
</NeoProvider>Dark Mode
rn-neo does not manage dark mode automatically. You decide when to switch themes
and how to detect the user's preference. A common pattern using React Native's
useColorScheme:
import { useColorScheme } from 'react-native';
import { NeoProvider, DefaultLightTheme, DefaultDarkTheme } from 'rn-neo';
export default function App() {
const scheme = useColorScheme();
const theme = scheme === 'dark' ? DefaultDarkTheme : DefaultLightTheme;
return (
<NeoProvider theme={theme}>
<YourApp />
</NeoProvider>
);
}Customizing the Theme
The theme prop accepts a NeoTheme object. Every field is optional — spread the
built-in theme and override only what you need.
import { DefaultLightTheme } from 'rn-neo';
import type { NeoTheme } from 'rn-neo';
const myTheme: NeoTheme = {
...DefaultLightTheme,
colors: {
...DefaultLightTheme.colors,
primary: '#6600FF',
onPrimary: '#FFFFFF',
},
radius: 'md',
shadowSize: 'lg',
animation: false,
};NeoTheme Reference
| Prop | Type | Default | Description |
|---|---|---|---|
dark | boolean | false | Marks the theme as dark. Used internally. |
colors | ColorTokens | — | Full color token map. |
radius | Radius | 'none' | Default radius for all components. |
borderSize | BorderSize | 'medium' | Default border width for all components. |
shadowSize | ShadowSize | 'md' | Default shadow offset for all components. |
border | boolean | true | Show borders globally by default. |
shadow | boolean | true | Show shadows globally by default. |
animation | boolean | true | Enable animations globally. |
animationDuration | number | 100 | Duration for animations in ms. |
Color Tokens
Colors are defined as a flat map of semantic token names to hex strings. Every
token has a foreground counterpart (e.g. primary and onPrimary) that
components use for text and icons rendered on top of that color.
| Token | Pair | Usage |
|---|---|---|
primary | onPrimary | Main brand color |
secondary | onSecondary | Accent color |
error | onError | Destructive states |
success | onSuccess | Positive feedback |
warning | onWarning | Cautionary states |
background | onBackground | Screen background |
surface | onSurface | Card and container backgrounds |
border | — | Default border color |
shadow | — | Default shadow color |
muted | — | Subdued text and icons |
Customizing the Config
The config prop accepts a NeoConfig object. It defines the concrete pixel
values for every design token used across the library, and maps font weight names
to font families.
Like theme, it supports partial overrides.
import type { NeoConfig } from 'rn-neo';
const myConfig: NeoConfig = {
spacing: {
'xs': 4,
'sm': 8,
'md': 12,
'lg': 16,
'xl': 20,
'2xl': 28,
'3xl': 36,
},
fonts: {
normal: 'Inter-Regular',
medium: 'Inter-Medium',
bold: 'Inter-Bold',
},
};
<NeoProvider config={myConfig}>
<App />
</NeoProvider>;NeoConfig Reference
Radius tokens (Radius)
| Token | Default (px) |
|---|---|
none | 0 |
sm | 4 |
md | 8 |
lg | 12 |
xl | 16 |
full | 999999 |
Border size tokens (BorderSize)
| Token | Default (px) |
|---|---|
none | 0 |
thin | 1 |
medium | 2 |
thick | 3 |
Shadow size tokens (ShadowSize)
| Token | Default (px) |
|---|---|
sm | 2 |
md | 4 |
lg | 8 |
Spacing tokens (Spacing)
| Token | Default (px) |
|---|---|
xs | 2 |
sm | 4 |
md | 8 |
lg | 12 |
xl | 18 |
2xl | 24 |
3xl | 30 |
Font size tokens (FontSize)
| Token | Default (px) |
|---|---|
sm | 12 |
md | 14 |
lg | 16 |
xl | 20 |
2xl | 24 |
3xl | 28 |
Font weight tokens (FontWeight)
Maps weight names to font family strings. The library uses these internally when
rendering text with a specific fontWeight prop.
| Token | Default |
|---|---|
normal | 'System' |
medium | 'System' |
bold | 'System' |
To use custom fonts, link them to your project first (via the Expo plugin or
npx react-native-asset for bare React Native), then pass their names here:
fonts: {
normal: 'SpaceGrotesk-Regular',
medium: 'SpaceGrotesk-Medium',
bold: 'SpaceGrotesk-Bold',
}Component-Level Overrides
Every style prop you pass directly to a component takes priority over the theme default. You don't need to touch the theme to change how one specific component looks.
// Uses theme defaults
<Box />
// Overrides radius and shadow for this instance only
<Box radius="lg" shadowSize="sm" shadowColor="primary" />
// Disables border for this button only
<Pressable border={false}>
<Text>Click me</Text>
</Pressable>This works for border, borderSize, borderColor, radius, shadow,
shadowSize, shadowColor, backgroundColor, and all spacing props across
every component that supports them.
useNeo()
The useNeo hook gives you direct access to the active theme and config anywhere
inside your component tree. Useful when you're building custom components and want
them to stay consistent with the rest of your UI.
import { useNeo } from 'rn-neo';
function MyComponent() {
const { theme, config } = useNeo();
return (
<View
style={{
backgroundColor: theme.colors.surface,
padding: config.spacing.md,
borderRadius: config.radius.lg,
}}
/>
);
}theme gives you the full resolved NeoTheme and config gives you the full
resolved NeoConfig — both with your overrides already merged in.