Review the default RNUI visual language in one place — typography, controls, elevated surfaces, and status treatments. Use this page after token or component changes to confirm nothing regressed.
Source of truth: .planning/rnui-design-foundation-contract.md
Layer Rule Surfaces Fill + border required; shadow optional depth only Borders default for shells, input for fields, subtle for dividers — all perceptibleRadius lg buttons/inputs, xl cards/modals — not pill-by-defaultShadow Soft mobile-native elevation; no Bootstrap black slabs Status bg + border + text on every severity States Focus, disabled, pressed, selected use semantic tokens
Native example app is the source of truth — CSS previews below approximate tokens. Run the SurfaceVisibility screen in apps/example after token changes.
Automated guardrail: bun run build && bun run surface:audit
Family Pass criteria Layout (Card, Paper, Divider) Visible with shadow.none Actions (Button, Toggle) Outline/ghost/disabled readable Forms (Input, FormGroup) Visible inside Card Status (Badge, Alert, Toast) bg + border + text Overlay (Modal, Menu, Select) Panel border + fill Data (List, Table, Tabs) Row/tab separation without shadow-only
Hierarchy should feel mobile-native: clear steps without overpowering body copy.
Design systems that feel native RNUI pairs semantic tokens with polished components so your product reads consistently on iOS and Android without reinventing spacing, color, or type on every screen.
Why teams choose RNUI Ship faster with accessible defaults, subtle elevation, and motion that respects reduced-motion preferences.
Updated 2 days ago · 4 min read
Default radius is rounded-lg (not pill). Solid actions stay premium with soft elevation; outline and ghost stay lightweight.
Upgrade to Pro Unlock offline mode, shared workspaces, and priority support for your team.
Start free trial Learn more
Variants
Primary Outline Ghost Delete
Native-friendly 44px height (aligned with Button md), soft borders, and readable placeholder text.
Elevated surfaces use subtle border + soft shadow — border and fill must remain visible with shadow disabled (see No-shadow section below).
Alex Morgan Product designer · San Francisco. Usually replies within a few hours.
Message View profile
Weekly summary 12 tasks completed · 3 meetings · Focus time up 18% from last week.
Every variant includes background, border, and text so pills read on normal app backgrounds.
On app background
Shipped Delayed Failed In transit
Orders
#1042 — Studio desk Delivered
#1041 — Monitor arm Processing
#1040 — Cable kit Draft
Account
Subscription Pro
Security Action needed
All variants
Default Brand Accent Success Warning Error Info
Status surfaces stay refined — elevated toast and snackbar cards (not heavy inverse slabs). Alerts use severity borders on standard variant.
Chips
Product Draft Filter Live
New version available
Update to 2.4 for faster sync and improved offline mode.
Payment method expiring
Your card ends in 12 days. Update billing to avoid interruption.
✓ Profile saved
Your changes are live across all devices.
! Could not upload photo
Check your connection and try again.
Changes saved Undo
Controls
Push notifications Marketing emails✓ Remember this device Share analytics
Status components must be visible without relying on iOS glass, blur, notification-shade blending, or dark overlays.
White surface
Default Brand Accent Success Warning Error Info
Brand Neutral Active
App background
Default Brand Accent Success Warning Error Info
Brand Neutral Active
Card surface
Default Brand Accent Success Warning Error Info
Brand Neutral Active
Glass surface
Default Brand Accent Success Warning Error Info
Brand Neutral Active
Dark surface
Default Brand Accent Success Warning Error Info
Brand Neutral Active
Background — status fill must differ from the surface behind it
Border — 1px semantic border defines the edge
Text — semantic text color stays readable (WCAG AA on the fill)
No blur dependency — if a badge only looks correct over glass, the tokens are wrong
Surface Token reference White #FFFFFFApp background color.bg.defaultCard color.surface.raisedGlass color.glass.surfaceDark color.surface.default (dark)
CSS demos above approximate tokens — overlays must be verified in the example app on iOS and Android.
Component Example screen Native checks Modal apps/example/app/components/Modal.tsxInset, safe area, keyboard form, animation Dialog Dialog.tsxHost inset, actions slot, form input AlertDialog AlertDialog.tsxDestructive confirm, button layout Alert Alert.tsxCompound title + body severity colors
Run: cd apps/example && bun run ios (or android). Full checklist: Example app guide .
Light + dark on iPhone-sized simulator and one Android emulator:
Modal/Dialog never flush to screen edges (host inset visible)
Form-in-modal: primary action stays above keyboard (iOS)
Alert title + body share severity hue without manual color props
Toast action label readable; Snackbar uses elevated surface
Badge default and accent readable on app background
Backdrop tap and hardware back dismiss where onClose is set
Repo copy: .planning/device-qa-checklist.md
Components must remain visible when shadow/elevation is disabled. Shadow may add depth but must never be required for recognition.
App background
Default Success Error
Solid Outlined
Info alert
Visible without shadow.
Email
Outline Ghost Disabled
Card surface
Default Success Error
Solid Outlined
Info alert
Visible without shadow.
Email
Outline Ghost Disabled
White surface
Default Success Error
Solid Outlined
Info alert
Visible without shadow.
Email
Outline Ghost Disabled
Glass surface
Default Success Error
Solid Outlined
Info alert
Visible without shadow.
Email
Outline Ghost Disabled
Dark surface
Default Success Error
Solid Outlined
Info alert
Visible without shadow.
Component No-shadow check Card White fill + border.default on bg.default Paper Border + fill at elevation none Badge / Chip Fill + border on app, card, and glass panels Alert Severity bg + 1px border Input surface.default fill + border.inputButton outline/ghost Border or brand text — not shadow-dependent Disabled Reduced opacity but still readable
App background (color.bg.default)
White / card surface (color.surface.default / raised)
Glass-like panel (color.surface.glass)
Dark panel (color.bg.inverse or dark surface.default)
Native QA: example app screen SurfaceVisibility — full A–G matrix (neutral, form, status, action, data, overlay notes, dark panel) with real RNUI components.
Hard rules enforced by tokens, component recipes, and bun run surface:audit:
Fill first — component background must differ from the parent canvas (bg.default, surface.default, or surface.raised) without relying on shadow.
Border required — 1px semantic border (border.default, border.input, or status border) must remain perceivable on light and dark surfaces.
Shadow is optional depth — shadow.sm and up may enhance elevation; removing shadow must not hide the component.
Status triple — Badge, Chip, Alert, Toast variants need background + border + text on app, white, card, glass, and dark panels.
Nested surfaces — Card-on-Card uses surface.raised inner fill; FormGroup grouped uses outer border; Input keeps border.input inside Card.
Glass fallback — translucent fills (surface.glass) pair with visible surface.glassBorder.
Brand themes — bg.default and surface.default must not collapse; borders strengthened per brand tint.
Reference docs: .planning/surface-visibility-contract.md · audit: scripts/audit-surface-contrast.mjs
Final truth is the native example app — CSS demos approximate tokens; run SurfaceVisibility on iOS/Android simulators after token changes.