home / skills / tristanmanchester / agent-skills / styling-nativewind-v4-expo

styling-nativewind-v4-expo skill

/styling-nativewind-v4-expo

This skill configures NativeWind v4 with Expo React Native to enable Tailwind-style className utilities, theming, and reliable CSS integration.

npx playbooks add skill tristanmanchester/agent-skills --skill styling-nativewind-v4-expo

Review the files below or copy the command above to add this skill to your agents.

Files (6)
SKILL.md
4.6 KB
---
name: styling-nativewind-v4-expo
description: >-
  Sets up and uses NativeWind v4 (Tailwind CSS v3) in Expo React Native apps, including Expo Router.
  Configures tailwind.config.js, global.css, babel.config.js (jsxImportSource + nativewind/babel),
  metro.config.js (withNativeWind + input), and app.json (web bundler metro).
  Troubleshoots “className not applying”, Tailwind CLI compilation, and Metro cache issues.
  Implements reusable components/variants, dark mode + theming via CSS variables (vars/useColorScheme),
  and third-party component styling (remapProps/cssInterop).
  Use when working on Expo projects using NativeWind v4, Tailwind-style className utilities, or when debugging NativeWind configuration.
---

# NativeWind v4 for Expo (React Native)

## Non‑negotiables (v4)

- Use Tailwind CSS v3 and include `presets: [require("nativewind/preset")]` in `tailwind.config.js`.
- Keep exactly one Tailwind entry CSS file (commonly `global.css`) and keep its path consistent across:
  - `metro.config.js` → `withNativeWind(..., { input: "./global.css" })`
  - your app entry → `import "./global.css"` (or `import "../global.css"` from `app/_layout.tsx`)
- Keep `nativewind/babel` in **Babel `presets`** and set `jsxImportSource: "nativewind"` on `babel-preset-expo`.
- After any config change, restart Metro **without cache**: `npx expo start --clear`.

## Quick start checklist

Copy/paste and tick off:

- [ ] Install deps (NativeWind + Tailwind + peers). See `references/expo-setup.md`.
- [ ] Create/verify `tailwind.config.js` (content globs + `nativewind/preset`).
- [ ] Create/verify `global.css` with Tailwind directives.
- [ ] Create/verify `babel.config.js` (jsxImportSource + `nativewind/babel`).
- [ ] Create/verify `metro.config.js` (wrap config with `withNativeWind`, set `input`).
- [ ] If targeting web, set `app.json` → `expo.web.bundler = "metro"`.
- [ ] If TypeScript, add `nativewind-env.d.ts` with `/// <reference types="nativewind/types" />`.
- [ ] Start with cache cleared and validate on-device + web: `npx expo start --clear`.
- [ ] Validate with an obvious “smoke test” screen: background colour + centred text.

## Project type selection

- **Expo Router**: entry is usually `app/_layout.tsx` → import CSS there (relative path is typically `../global.css`).
- **Classic**: entry is usually `App.tsx` → import CSS there (`./global.css`).

If unsure, search `package.json` for `"main": "expo-router/entry"`.

## Implementation patterns

### Build reusable components (recommended)

Accept `className`, merge defaults, and optionally use a class-variance helper.

Read: `references/patterns.md`

### Style third‑party components (only when necessary)

Use `remapProps` (multiple style props) or `cssInterop` (map a class prop to a style prop).

Read: `references/third-party-components.md`

### Dark mode + theming

Use `useColorScheme` / `colorScheme.set()` and CSS variables via `vars()`.

Read: `references/theming-dark-mode.md`

### Safe area utilities

On Expo Router, do **not** add your own `SafeAreaProvider` (Router already does).
Use `p-safe`, `pt-safe`, etc.

If you are **not** using Expo Router, wrap the root with `SafeAreaProvider`.

## Troubleshooting workflow (always in this order)

1. Start Expo without cache: `npx expo start --clear`.
2. Verify Tailwind CLI works by compiling your CSS entry file to an output file.
3. Confirm the “three paths” match:
   - CSS file exists
   - `metro.config.js` `input` points to it
   - your app imports it from the entry component
4. Confirm `tailwind.config.js` `content` globs include every directory that contains `className` strings.
5. Only then debug platform-specific behaviour (web bundler, Router, safe area, etc).

Read: `references/troubleshooting.md`

## THE EXACT PROMPT — NativeWind v4 config audit

Use this prompt to perform a deterministic audit of an existing repo:

```
You are auditing an Expo React Native repo for NativeWind v4 correctness.

1) Identify whether the project uses Expo Router (app/ directory + package.json main = expo-router/entry) or classic App.tsx.
2) Check and report on:
   - tailwind.config.js: presets + content globs
   - global.css: Tailwind directives exist
   - babel.config.js: jsxImportSource nativewind + nativewind/babel in presets; preserve any existing required plugins
   - metro.config.js: withNativeWind wrapper; input path matches the CSS file
   - app.json: web bundler metro when web is used
   - TypeScript: nativewind-env.d.ts present and correctly named
3) For every issue, propose the minimal diff needed to fix it.
4) End by listing the exact commands to restart Metro and validate the fix.
```

Overview

This skill sets up and audits NativeWind v4 (Tailwind CSS v3) in Expo React Native apps, including projects using Expo Router. It enforces required configs, fixes common pitfalls, and provides minimal diffs and commands to validate fixes. Use it to get className utilities working reliably across iOS, Android, and web.

How this skill works

The skill inspects project structure to detect Expo Router vs classic App entry, then checks key files: tailwind.config.js, global.css, babel.config.js, metro.config.js, app.json, and nativewind TypeScript declarations. It validates the three-path relationship (CSS file exists, metro input matches, app imports CSS), verifies Babel and Metro wrappers, and looks for Tailwind directives and content globs. For each issue found it proposes the smallest configuration diff and exact commands to restart Metro and recompile Tailwind.

When to use it

  • Integrating NativeWind v4 into a new or existing Expo project.
  • Migrating to or validating Tailwind CSS v3 with NativeWind preset.
  • Debugging className not applying or inconsistent styling on web/mobile.
  • Configuring Expo Router to import the single global CSS entry.
  • Ensuring Metro and Babel configuration are compatible with nativewind/babel.

Best practices

  • Keep exactly one Tailwind entry CSS file (commonly global.css) and reference it consistently in metro.config.js and your app entry.
  • Add presets: [require('nativewind/preset')] to tailwind.config.js and include content globs for every folder with className usage.
  • Add nativewind/babel to Babel presets and set jsxImportSource: 'nativewind' on babel-preset-expo.
  • After any config change, restart Metro without cache: npx expo start --clear.
  • If using Expo Router import the CSS from app/_layout.tsx (typically ../global.css); for classic apps import in App.tsx.

Example use cases

  • Run a deterministic audit to find why className styles aren’t applied on Android but work on iOS.
  • Add Dark mode and theming using CSS variables and useColorScheme with minimal config changes.
  • Fix Metro caching or Tailwind CLI compilation issues by validating the three-path setup and clearing cache.
  • Style a third-party component by using remapProps or cssInterop patterns when direct className mapping fails.
  • Validate TypeScript projects have nativewind-env.d.ts and correct typings for className utilities.

FAQ

What exactly are the “three paths” I must verify?

Ensure the CSS file exists, metro.config.js withNativeWind input points to that file, and your app entry imports that same file.

When should I clear the Metro cache?

Always after changing Babel, metro.config.js, tailwind.config.js, or the CSS entry. Use npx expo start --clear.

How do I handle Expo Router vs classic apps?

For Expo Router import the global CSS in app/_layout.tsx (relative path usually ../global.css). For classic apps import in App.tsx.