Delacour UI · Native

React Native components that compose.

Built on Uniwind, Reanimated and the Gesture API. Nineteen components, 148 typed surfaces, and a reason written down for every decision.

bun add @delacour/native-ui

The icon names nothing

No size, no color. The button wraps its subtree in an icon-defaults provider carrying its own size class and its variant's foreground token, so a bare glyph comes out right with nothing said at the call site.

Set either explicitly and yours wins. That is the whole precedence rule, and it is the same one every component here follows.

How composition works
import { Button } from "@delacour/native-ui/button";import { Icon } from "@delacour/native-ui/icon";import { IconArrowRight } from "@delacour/native-ui/icons/central";<Button haptic="selection" onPress={next}>  <Button.Label>Continue</Button.Label>  <Icon icon={IconArrowRight} /></Button>;

Why it is built this way

Compose, don't configure

Icons are children, never props. A button publishes its size and its variant's foreground to the subtree, so a bare <Icon> comes out matching the label beside it.

Loading that costs no layout

The spinner takes the place of the icon it replaces rather than joining it. Both are drawn at the same token, so nothing shifts when work begins — or when it ends.

One scale, indexed

Icon and Spinner resolve md to the same edge length. A checkbox's square reads that scale two steps up rather than minting its own three numbers.

Themed by CSS variables

Components name bg-background and text-muted-foreground — never a raw palette colour, never a dark: prefix. Swap the variables and the theme follows.

Decisions you can unit-test

Every pure resolver lives in a *.variants.ts free of React Native imports, so the whole variant matrix is reachable from bun test rather than only from a simulator.

Peers, not dependencies

Every native module is a peer, and granular export subpaths make the optional ones genuinely optional. Import /button and nothing keyboard-related resolves.