Quick start

A themed, pressable Button on a simulator, in two commands and two files.

By the end of this page an Expo app is running on a simulator with a Button that counts its presses, styled from the same tokens as your web app.

One command does the setup: add writes native-components.json, wraps Metro with Uniwind's transform, points Tailwind at the components, copies the theme and the root provider in, and then copies what you asked for. Nothing is explained here — every command is copyable, and each links to the page that does explain it.

Start here

A new app

Create it

bunx create-expo-app@latest my-app -e with-router-uniwind
cd my-app

Expo's with-router-uniwind example, which arrives with Expo Router, Uniwind and Tailwind already wired and its CSS entry imported. Any Expo app works — this one is simply the shortest path to a themed screen.

Add a Button

bunx delacour@latest add button --install

It finds the Uniwind setup this template already has, adds its own block to src/global.css rather than a second file, and copies button and the parts it renders into src/components/ui/. --install runs the installs; leave it off to see the commands first.

Then use your first component.

An existing app

One command, from the app's root:

bunx delacour@latest add button --install

It sets Uniwind up for you

These components are styled with Uniwind — Tailwind CSS v4 for React Native. It is what compiles every className in the source you are about to own, so the app needs it whichever way you install.

There is no separate step: on a project that has none, add installs uniwind and tailwindcss through expo install, wraps metro.config.js with withUniwindConfig outermost, and writes a Tailwind entry importing both. A project that already has Uniwind keeps its own setup — its CSS entry is read off the Metro config rather than replaced.

Uniwind's own installation guide is worth reading for what its Metro options do and for the editor IntelliSense settings, neither of which the CLI touches.

NativeWind cannot stay

NativeWind is Tailwind for React Native too, and it also compiles className by wrapping Metro. Two transforms in one Metro config resolve classes through whichever wrapper ran last and fail naming neither library. Move across first — Uniwind's migration guide is a few minutes — and delacour doctor will say so if you forget.

Where the components land

In a workspace add asks whether they belong to the app or to a package several apps share. Monorepos covers that, and init is how to decide it without being asked.

Then use your first component.

Let your agent do it

Install the skill and your assistant copies real components instead of writing plausible ones:

bunx delacour@latest skills

Or paste this into any agent, with nothing installed:

Paste this into your coding agent

Set up Delacour UI in this React Native / Expo project.

Use the delacour CLI as the source of truth for what exists and what it needs. Do not write any
component from memory, and do not guess a package version.

First, look at the project:
1. Detect the package manager (bun / npm / pnpm / yarn) from the lockfile, and whether this is a
   bare React Native app or Expo. Find the app's root — the package that depends on `expo`.
2. Read package.json. Note whether Uniwind and Tailwind are already installed. If NativeWind is
   there, STOP and tell me — it compiles className and wraps Metro too, and two Tailwind transforms
   cannot share one Metro config.
3. Find the app entry (App.tsx, app/_layout.tsx, index.tsx) and check whether a
   GestureHandlerRootView already wraps the app. If one is there, reuse it — do not nest a second.

Then install:
- Run `bunx delacour@latest add button --install` (spelled for this project's package manager).
  That writes native-components.json, wraps Metro with Uniwind's transform, points Tailwind at the
  components, copies the theme and the root provider in, and adds Button. There is no separate
  setup step.
- Run whatever install commands it prints, verbatim, from the app root. Native modules go through
  `expo install`, never the package manager — the newest release fails at the linker.

Then make the two edits it cannot make for me, because both are in files I own:
- Import the CSS entry as the FIRST statement of the root layout. Without it every component
  renders unstyled and nothing logs an error.
- Wrap the app in <DelacourProvider> from the copied provider. Without it presses stop landing,
  just as silently.

Finally:
- Run `bunx delacour@latest doctor` and fix anything it names.
- Run `bunx delacour@latest list` to see what else is available, and add components by name rather
  than writing them.
- Component reference: https://ui.delacour.co.nz/llms.txt, or any docs page with .md appended.

When you are done, tell me what changed and how to run the app on iOS and Android.

Use your first component

Both paths land here. Two files: mount the provider once at the root, then use the component.

src/app/_layout.tsx
import "../global.css";
import { DelacourProvider } from "../components/ui/provider";
import { Slot } from "expo-router";

export default function Layout() {
  return (
    <DelacourProvider>
      <Slot />
    </DelacourProvider>
  );
}
src/app/index.tsx
import { Button } from "../components/ui/button";
import { useState } from "react";
import { View } from "react-native";

export default function Index() {
  const [count, setCount] = useState(0);

  return (
    <View className="flex-1 items-center justify-center gap-4 bg-background">
      <Button onPress={() => setCount(count + 1)}>Pressed {count} times</Button>
      <Button variant="outline" onPress={() => setCount(0)}>
        Reset
      </Button>
    </View>
  );
}

The imports are relative because this template declares no path aliases. Add "paths": { "@/*": ["./src/*"] } to tsconfig.json and experiments.tsconfigPaths: true to your Expo config and the CLI writes @/components/ui/button instead — the form every component page shows.

Both of these are silent failures

The CSS import must be the first statement of the root layout — this template already has it, and without it every component renders unstyled with nothing logged. DelacourProvider is the gesture root every press needs above it; leave it out and presses stop landing, just as quietly.

Run it

bunx expo run:ios

The components use native modules — Reanimated, Gesture Handler — so this is a native build, not Expo Go. The first one takes a few minutes; expo run:android is the same command for Android.

Check the wiring

bunx delacour@latest doctor

Every check is a failure that produces no error on its own. If the button rendered and counts, it passes; if something is off, doctor names the file and the fix.

Next

On this page