expo-design-system
Build and maintain a design system inside an Expo app: design tokens, component variant conventions, extending NativeWind, Tamagui, Restyle or Unistyles, fixing apps that look AI-generated, and auditing for design-system drift.
Install
npx skills add https://github.com/expo/skills --skill expo-design-systemDesign System Audit
Measure how far an existing Expo app has drifted from a single visual source of truth, then document or extend components with a consistent template.
Run the audit before proposing changes. Report findings first; apply fixes only when asked.
0. Locate the directories first
Do not assume a src/ folder. The default create-expo-app template puts app/, components/, and constants/ at the repo root, and running the checks below against a nonexistent src/ returns zero hits - a false clean bill.
Before any grep, identify and record:
- Source directories - every directory holding app code (
src, or e.g.app components constants hooks). - Theme location - the token directory or file (
src/theme,theme,constants, or a singletheme.ts). If none exists yet, note that as the first finding. - The existing system, if any - a styling library in
package.json(NativeWind, Tamagui, Restyle, Unistyles, styled-components) perSKILL.md"Adopt Before You Build". Record which one. The checks below assume this skill's defaults - plainStyleSheet,boxShadowstrings, onesrc/themeentry point. An app on a styling library fails several of them while being perfectly consistent in its own idiom. Audit such an app against its own system: its token names, its scale, its config file as the single entry point. Adapt or skip a check rather than reporting a false violation.
Substitute them into the shell variables below; every check uses them.
1. Token coverage checks
Run from the repo root. Each hit outside the theme directory is a candidate for tokenization - not automatically a violation (check for the "one-off, with a comment" exemption in SKILL.md).
Then run the candidate checks in native-slop.md. Inspect the rendered result: token checks alone cannot establish readable dark mode, spacing hierarchy, or appropriate shadows.
For a Tailwind project, also check for values that bypass global.css variables: arbitrary-value classes like p-[13px] or text-[#5B21B6].
2. Scoring
Turn raw hit counts into a comparable score so runs can be tracked over time:
For each category: score = escapes per 100 source lines (hits ÷ SLOC × 100, one decimal).
Report the per-category scores in the summary. The overall priority order falls out of the scores: the highest-scoring category is usually the first migration target.
3. Component completeness
For each component in the shared components directory (src/components/, or components/ in a root-level layout), check it against the contract in SKILL.md:
4. Report format
5. Adopting incrementally
An app with dozens of escapes is migrated in order, never big-bang. A big-bang conversion produces one huge unreviewable diff and usually stalls half-done.
- Create the tokens first. Derive the scales from the values the audit found most often, snapped to the grid. A theme built from the app's real values gets adopted; an aspirational one gets bypassed.
- Typography before spacing. Convert raw
fontSizeto thetyperamp +ThemedTextfirst: it is the highest-visibility win and touches the fewest layout decisions. Then spacing, then colors, then radius/shadows. - Convert one worst-offender file completely and use it as the reference pattern for the rest of the migration.
- Then convert per-screen, one screen per commit, using the audit greps scoped to that screen to verify it comes out clean.
- Re-run the audit after each phase and record the scores from §2 - they should fall monotonically.
6. Documenting an existing component
7. Proposing a new component
Before designing a new primitive, prove the existing set can't cover it:
If the "what's missing" column is empty for any row, extend that component's variants instead of adding a new one.