Bring your design system
KitProvider, and every component you add matches your app — no edits to the copied files.Start with init
init asks for a brand colour, font, radius and light / dark, or takes them as flags. It adds lib/kit.tsx and writes lib/kit-theme.tsx: an <AppTheme> wrapper around KitProvider. Wrap your root layout in it, then fill in colors below.
Which token is which
Every component reads these from useKit().colors. You don't have to set them all: anything you leave out keeps the kit default for that scheme.
| Prop | Type | Default |
|---|---|---|
| background Screen and page fill. Point it at your screen background. | string | #ffffff |
| foreground Main text and icons. Point it at your primary text colour. | string | #09090b |
| card / cardForeground Cards, inputs, sheets — and the text on them. Point it at your surface and its text. | string | #ffffff / #09090b |
| popover Raised surfaces: toasts, menus. Point it at your elevated surface. | string | #ffffff |
| muted Subtle fills: tracks, skeletons, pressed rows. Point it at your subtle / secondary surface. | string | #f4f4f5 |
| mutedForeground Secondary text, placeholders, captions. Point it at your secondary text. | string | #71717a |
| border / input Hairlines; field outlines. Point it at your divider and input-border colours. | string | #e4e4e7 / #d4d4d8 |
| primary / primaryForeground Default solid buttons and their label. Point it at your primary button fill and label. | string | #18181b / #fafafa |
| secondary / secondaryForeground Quiet buttons and chips. Point it at your secondary button fill and label. | string | #f4f4f5 / #18181b |
| accent / accentForeground Brand colour: focus rings, selection, accent buttons. Point it at your brand colour (or pass accent=). | string | #18181b / #ffffff |
| success / warning / danger Status colours: toasts, alerts, validation. Point it at your semantic colours. | string | green / amber / red |
| dangerForeground Text on a danger fill. Point it at usually white. | string | #ffffff |
| ring Focus outline; follows accent when you pass one. Point it at your focus colour. | string | #18181b |
| overlay Scrim behind sheets and dialogs. Point it at your backdrop, with alpha. | string | rgba(0,0,0,0.4) |
The bridge
Keep your design system the source of truth and map it in one place. Light and dark are separate maps, so a token can point at different values per scheme.
import type { ReactNode } from "react"; import { KitProvider } from "@/lib/kit";import { tokens } from "@/theme/tokens"; // your existing design system export function AppTheme({ children }: { children: ReactNode }) { return ( <KitProvider scheme="system" accent={tokens.brand[500]} radius={tokens.radius.md} fontFamily={tokens.font.body} colors={{ light: { background: tokens.light.bg, foreground: tokens.light.text, card: tokens.light.surface, cardForeground: tokens.light.text, popover: tokens.light.surfaceRaised, muted: tokens.light.subtle, mutedForeground: tokens.light.textSecondary, border: tokens.light.divider, input: tokens.light.inputBorder, primary: tokens.brand[600], primaryForeground: "#ffffff", danger: tokens.red[500], }, dark: { background: tokens.dark.bg, foreground: tokens.dark.text, card: tokens.dark.surface, muted: tokens.dark.subtle, mutedForeground: tokens.dark.textSecondary, border: tokens.dark.divider, }, }} > {children} </KitProvider> );}import { Stack } from "expo-router";import { AppTheme } from "@/lib/kit-theme"; export default function RootLayout() { return ( <AppTheme> <Stack /> </AppTheme> );}Radius and font
radius is your base corner in points (default 12); the kit derives sm, lg and xl from it and scales pills and bars to match, so radius={0} gives a square UI. fontFamily must be a font your app has loaded (for example with expo-font) before the first screen renders.
Light and dark
scheme="system" follows the device. If your app has its own appearance setting, pass its value instead — scheme={appearance} with "light" or "dark" — and the kit follows your switch rather than the device's.
useKit(), so custom components and kit components can't drift apart. Keep the bridge in kit-theme.tsx rather than editing kit.tsx: then update can refresh kit.tsx without stopping on your changes.
