Skip to content
Mobile
Skill

/theming

Scaffold a unified, cross-platform color theme system into an Expo Router app. Sets up semantic system colors (resolved from native iOS labels and Android Material You dynamic colors), brand colors, automatic dark/light re-rendering, the React Navigation ThemeProvider, and a

BOOST
From plugin
code-with-beto-skills
1434 skills
Install
$ npx -y skills add Code-with-Beto/skills --skill theming --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/theming

Context preview

The summary Claude sees to decide when to auto-load this skill.

Scaffold a unified, cross-platform color theme system into an Expo Router app. Sets up semantic system colors (resolved from native iOS labels and Android Material You dynamic colors), brand colors, automatic dark/light re-rendering, the React Navigation ThemeProvider, and a

SKILL.md

theming.SKILL.md
name: theming
description: Scaffold a unified, cross-platform color theme system into an Expo Router app. Sets up semantic system colors (resolved from native iOS labels and Android Material You dynamic colors), brand colors, automatic dark/light re-rendering, the React Navigation ThemeProvider, and a useColors() / useTheme() context hook. Use whenever a user wants to set up theming, dark mode, dynamic or Material You colors, a unified color system, or a useColors/useTheme hook in an Expo / React Native app, even if they do not name a specific approach.

Expo Unified Theming

Set up one color system that works on iOS and Android at once. Instead of sprinkling `Color.ios.*` and `Color.android.dynamic.*` (or hardcoded hex) all over the app, the user gets semantic tokens (`background`, `text`, `link`, ...) that resolve to the right native color per platform, flip with dark/light automatically, and are read through a single `useColors()` hook.

This is the pattern from the **Platano** template, packaged so it drops into any Expo Router app.

What gets installed

Three files (bundled in `assets/`, adapt them to the project):

  • `config.ts` — the single source of truth. Semantic system tokens set to

`"native"` or a hex, plus brand colors. This is the only file the user edits day to day.

  • `colors.ts` — resolves tokens to real colors per platform, exposes

`getSystemColor`, `useSystemColors`, the brand helpers, and `getNavigationTheme`.

  • `ThemeContext.tsx` — `ColorsProvider` + the `useColors()` / `useTheme()` /

`useBrand()` hooks built on React's `use`.

Plus a small edit to the root `_layout.tsx` to wire the providers.

The two ideas that make this work

Explain these to the user, because they are the whole point and the two things people get wrong:

1. **Re-render on theme change.** Native and Material You colors are platform color objects, not strings React can diff. The signal that the theme changed is `useColorScheme()`. So the resolvers take the color scheme as an argument even when they do not read it: that makes dark/light an explicit dependency, and the value recomputes when the user toggles. The `ColorsProvider` reads `useColorScheme()` once near the root, so a toggle re-renders every consumer.

2. **Two ThemeProviders, different jobs.** `ColorsProvider` (this skill) feeds `useColors()` to your components. The navigation `ThemeProvider` themes the navigation chrome (headers, tab bars, default background). Both live at the root. Wire navigation's with `getNavigationTheme(dark)` so the chrome matches your tokens. Do not confuse them or drop one. On **Expo SDK 56+** the navigation theme bits (`ThemeProvider`, `DarkTheme`, `DefaultTheme`, `Theme`) import from `expo-router/react-navigation`; on **older SDKs** they come from `@react-navigation/native` instead (see Step 1).

Step 1: Confirm the project, SDK, and the native Color API

This skill targets **Expo Router** apps on **Expo SDK 56 or newer**. SDK 56 is where the `Color` API (iOS system colors + Android Material You) and the `expo-router/react-navigation` re-exports the templates use both ship. Check the SDK and the `Color` API before relying on `"native"` tokens.

# Find the project's app dir and root layout (root-level or under src/)
ls app/_layout.tsx src/app/_layout.tsx 2>/dev/null

# Check the installed Expo SDK major version
node -e "console.log('expo', require('expo/package.json').version)" 2>/dev/null

# Confirm expo-router exports the Color API
node -e "console.log('Color export:', !!require('expo-router').Color)" 2>/dev/null
grep -rl "android.dynamic\|ios.systemBackground" node_modules/expo-router/build 2>/dev/null | head -1

Branch on what you find:

  • **SDK 56+ (target):** use the templates as written. Navigation theme bits

import from `expo-router/react-navigation`.

  • **Older than SDK 56:** two adjustments are needed.

1. Import `ThemeProvider`, `DarkTheme`, `DefaultTheme`, and `type Theme` from `@react-navigation/native` instead of `expo-router/react-navigation` — in both `colors.ts` and `_layout.tsx`. (Older Expo Router did not re-export them, so you go to React Navigation directly.) 2. The `Color` API likely is not present. Either recommend upgrading to SDK 56, or use the **hex fallback**: keep the files but set the `system` tokens in `config.ts` to hex values instead of `"native"` (no Material You, but everything else works). `getBrandColors` still works; `isAndroidDynamic` resolves to false without `Color`.

Also detect the project's import alias from `tsconfig.json` (commonly `@/*` → `src/*` or the project root). Match that alias when you write imports. If there is no alias, use relative paths.

Step 2: Decide where the files live

Put the three files together in one folder so their relative imports (`./config`, `./colors`) just work. Mirror the project's layout:

  • App under `src/app/` → create `src/theme/`.
  • App at the root `app/` → create `theme/` at the root.

Check for an existing theme/colors module or a `ThemeProvider` first. If the app already has theming, do **not** clobber it. Read what is there, explain the overlap to the user, and either merge into their setup or place these files under a clearly named folder and let them migrate. Never blindly overwrite.

Step 3: Create the files

Copy the three bundled templates into the chosen folder, adapting:

  • import aliases / relative paths to match the project,
  • the `system` tokens and `brand` colors in `config.ts` to the user's brand (ask

for their brand primary/accent, or keep the sensible defaults and tell them where to change them).

Read each asset and write it into the project (do not just symlink — these are the user's files now):

  • `assets/config.ts` → `<theme>/config.ts`
  • `assets/colors.ts` → `<theme>/colors.ts`
  • `assets/ThemeContext.tsx` → `<theme>/ThemeContext.tsx`

Keep the comments. They explain the re-render trick and

Read more
Ships withcode-with-beto-skills

Professional agent skills and plugins to help mobile developers ship better apps faster with AI assistance.

Get the whole plugin
Stats
143
Stars
13
Forks
Maintained
Maintenance
TypeScript
Language
3mo ago
Last commit
8mo ago
Created
4h ago
Added

Repo: Code-with-Beto/skills

Other skills on code-with-beto-skills.