- Accordion
- Action Sheet
- Alert Dialog
- Alert
- Audio Player
- Audio Recorder
- Audio Waveform
- Avatar
- AvoidKeyboard
- Badge
- BottomSheet
- Button
- Camera Preview
- Camera
- Card
- Carousel
- Checkbox
- Collapsible
- Color Picker
- Combobox
- Date Picker
- File Picker
- Gallery
- Hello Wave
- Icon
- Image
- Input OTP
- Input
- Link
- MediaPicker
- Mode Toggle
- Onboarding
- ParallaxScrollView
- Picker
- Popover
- Progress
- Radio
- ScrollView
- SearchBar
- Separator
- Share
- Sheet
- Skeleton
- Spinner
- Switch
- Table
- Tabs
- Text
- Toast
- Toggle
- Video
- View
init
Use the init command to initialize a new BNA project with configuration and dependencies.
The init command creates a new project, installs dependencies, adds utils, hooks, themes and sets up the component structure for your mobile project.
pnpm dlx bna-ui init [project-name]
Options
Usage: bna-ui init [options] [project-name]
Scaffold a new Expo app with BNA UI set up
Arguments:
project-name Name of the project, or `.` for the current directory
Options:
--npm Install with npm
--yarn Install with yarn
--pnpm Install with pnpm
--bun Install with bun
--verbose Print the full error stack on failure
--skip-install Create the project without installing dependencies
-h, --help display help for command
Examples
$ bna-ui init my-app
$ bna-ui init . # scaffold into the current directory
$ bna-ui init my-app --pnpm --skip-installconvex
Use the convex command to initialize a new BNA project with Convex backend integration.
The convex command creates a new project with Convex configured, installs dependencies, and sets up the backend structure.
pnpm dlx bna-ui convex [project-name]
By default this scaffolds the full authentication setup — Google, Apple,
password and email OTP sign-in. Pass --no-auth for a Convex backend with no
sign-in at all: a schema, a demo query, and nothing to delete before you start.
pnpm dlx bna-ui convex [project-name] --no-auth
See Expo + Convex and Expo + Convex + Auth for what each one gives you.
Options
Usage: bna-ui convex [options] [project-name]
Scaffold a new Expo app with a Convex backend
Arguments:
project-name Name of the project
Options:
--npm Install with npm
--yarn Install with yarn
--pnpm Install with pnpm
--bun Install with bun
--verbose Print the full error stack on failure
--skip-install Create the project without installing dependencies
--skip-convex Skip provisioning the Convex backend
--no-auth Scaffold Convex without authentication
-h, --help display help for command
Examples
$ bna-ui convex my-app
$ bna-ui convex my-app --no-auth
$ bna-ui convex my-app --skip-convex # wire it up yourself latersupabase
Use the supabase command to initialize a new BNA project with a Supabase
backend — Postgres, row level security, realtime, storage and edge functions.
pnpm dlx bna-ui supabase [project-name]
By default this scaffolds the full authentication setup — password, magic links,
email OTP, Google, Apple and GitHub. Pass --no-auth for a backend with no
sign-in: migrations, a live query, storage and an edge function.
pnpm dlx bna-ui supabase [project-name] --no-auth
After copying files it asks for your project URL and publishable key, writes
them to .env.local, and then — only if the Supabase
CLI is on your PATH —
links the project, applies the migrations and generates
lib/database.types.ts. If it is not installed, those commands are printed as
next steps instead. Nothing fails either way.
See Expo + Supabase and Expo + Supabase + Auth for what each one gives you.
Options
Usage: bna-ui supabase [options] [project-name]
Scaffold a new Expo app with a Supabase backend
Arguments:
project-name Name of the project
Options:
--npm Install with npm
--yarn Install with yarn
--pnpm Install with pnpm
--bun Install with bun
--verbose Print the full error stack on failure
--skip-install Create the project without installing dependencies
--skip-supabase Skip linking the project and applying migrations
--no-auth Scaffold Supabase without authentication
-h, --help display help for command
Examples
$ bna-ui supabase my-app
$ bna-ui supabase my-app --no-auth
$ bna-ui supabase my-app --skip-supabasefirebase
Use the firebase command to initialize a new BNA project with a Firebase
backend — Cloud Firestore, Cloud Storage, and security rules with tests that
execute them.
pnpm dlx bna-ui firebase [project-name]
By default this scaffolds the full authentication setup — email and password,
Google and Apple, onboarding and a profile. Pass --no-auth for a backend with
no sign-in: a live task list, storage uploads with progress, and open rules.
pnpm dlx bna-ui firebase [project-name] --no-auth
After copying files it asks for your Firebase web config — deriving the auth
domain and storage bucket from the project ID as defaults — writes .env.local,
sets the default project in .firebaserc, and then, only if
firebase-tools is on your PATH,
selects the project and deploys the rules and indexes. If it is not installed,
those commands are printed as next steps instead. Nothing fails either way.
The CLI cannot create a project for you. You need one with a Web app added to it, plus Firestore and Storage enabled from the console's Build menu.
See Expo + Firebase and Expo + Firebase + Auth for what each one gives you.
Options
Usage: bna-ui firebase [options] [project-name]
Scaffold a new Expo app with a Firebase backend
Arguments:
project-name Name of the project
Options:
--npm Install with npm
--yarn Install with yarn
--pnpm Install with pnpm
--bun Install with bun
--verbose Print the full error stack on failure
--skip-install Create the project without installing dependencies
--skip-firebase Skip collecting the config and deploying the rules
--no-auth Scaffold Firebase without authentication
-h, --help display help for command
Examples
$ bna-ui firebase my-app
$ bna-ui firebase my-app --no-auth
$ bna-ui firebase my-app --skip-firebaseadd
Use the add command to add components and dependencies to your React Native or Expo project.
pnpm dlx bna-ui add [component]
Options
Usage: bna-ui add [options] [components...]
Add components to an existing project
Arguments:
components Component names. Omit to pick interactively.
Options:
--npm Install with npm
--yarn Install with yarn
--pnpm Install with pnpm
--bun Install with bun
--verbose Print the full error stack on failure
--overwrite Replace files that already exist
--dry-run Show what would be written, and write nothing
-y, --yes Skip prompts, keeping any existing files
--registry <url> Registry to fetch from
-h, --help display help for command
Examples
$ bna-ui add button
$ bna-ui add button input card
$ bna-ui add # browse and pick
$ bna-ui add button --dry-run
$ bna-ui add button --registry http://localhost:3000/rWhere components come from
add fetches component source from https://ui.ahmedbna.com/r and writes it
into your project. Responses are cached under ~/.cache/bna-ui and revalidated
with ETags, so repeat installs are fast and work offline.
Point it somewhere else with the --registry flag or the BNA_UI_REGISTRY
environment variable:
pnpm dlx bna-ui add button --registry http://localhost:3000/r
Adding a component brings its whole dependency chain — button also installs
the text, icon and spinner it composes, the hooks and theme files they
import, and any npm packages they need.
list
Every component, chart, hook and theme file the registry ships.
pnpm dlx bna-ui list npx bna-ui list --type chart
Options
Usage: bna-ui list|ls [options]
List every component, chart, hook and theme file
Options:
--type <type> Narrow to ui, chart, hook or theme
--json Emit as JSON, for scripts and agents
--registry <url> Registry to read from
--verbose Print the full error stack on failure
-h, --help display help for command
Examples
$ bna-ui list
$ bna-ui list --type chart
$ bna-ui list --jsonsearch
Find something without knowing its exact name.
pnpm dlx bna-ui search chart
Options
Usage: bna-ui search [options] <query>
Search the registry by name or description
Arguments:
query Search term, e.g. "chart" or "date"
Options:
--json Emit as JSON, for scripts and agents
--registry <url> Registry to read from
--verbose Print the full error stack on failure
-h, --help display help for command
Examples
$ bna-ui search chart
$ bna-ui search "date picker"info
A component's description, props, install command, source and examples — the
same bundle the MCP server serves. --json makes it machine-readable.
pnpm dlx bna-ui info button npx bna-ui info button --json
Options
Usage: bna-ui info [options] <component>
Print a component's props, source and examples
Arguments:
component Component name, e.g. button
Options:
--json Emit the full bundle as JSON, for scripts and agents
--registry <url> Registry to fetch from
--verbose Print the full error stack on failure
-h, --help display help for command
Examples
$ bna-ui info button
$ bna-ui info button --json | jq .metamcp
Runs an MCP server over stdio so an AI assistant can browse and read the registry itself. See MCP for editor configuration.
claude mcp add bna-ui -- npx -y bna-ui mcpThe server ships as a separate package, @bna-ui/mcp, and bna-ui mcp hands
off to it. That keeps the MCP SDK — which pulls in HTTP and SSE transport
dependencies this server never uses — out of every npx bna-ui add.
components.json
init writes one. It is optional: every command works without it, on the same
defaults. It exists so you stop repeating yourself.
{
"registry": "https://ui.ahmedbna.com/r",
"aliases": {
"components": "ui-kit"
},
"packageManager": "pnpm"
}| Key | Effect |
|---|---|
registry | Where add, list, search and info fetch from |
aliases | Where each kind of file is written, relative to the @/ root |
baseDir | Overrides where @/ points, when the tsconfig reading is wrong |
packageManager | Which manager installs npm dependencies |
Where files land
add writes relative to whatever your tsconfig.json maps @/* onto — the
same alias every installed file imports through. Nothing to configure:
"@/*" in your tsconfig | add button writes |
|---|---|
["./*"] | components/ui/button.tsx |
["./src/*"] | src/components/ui/button.tsx |
baseUrl is honoured, and jsconfig.json works the same way. Set baseDir to
override the detection — useful when the alias is declared in a base config you
extends rather than in the project's own tsconfig.
Aliases
aliases moves a kind of file to a different directory inside @/, and add
rewrites the matching import specifiers in the source it copies so everything
still resolves. With the config above, add button writes ui-kit/ui/button.tsx
and its imports read @/ui-kit/ui/text. Only the leading segment is remapped —
the ui/ beneath it is part of the registry's own layout.
Note these are relative to the @/ root, not to the project root. In an app
whose @/* maps to ./src/*, components already land under src/ — writing
"components": "src/components" would nest them twice, so add ignores the
redundant prefix and tells you to drop it.
Examples
Initialize a new project
pnpm dlx bna-ui init my-app
Initialize with Convex backend
pnpm dlx bna-ui convex my-convex-app
Initialize with Supabase backend
pnpm dlx bna-ui supabase my-supabase-app
Initialize with Firebase backend
pnpm dlx bna-ui firebase my-firebase-app
Initialize using specific package manager
pnpm dlx bna-ui init my-app --pnpm
Skip package installation
pnpm dlx bna-ui init my-app --skip-install
Add a button component
pnpm dlx bna-ui add button
Add multiple components
pnpm dlx bna-ui add button input card
Add component with overwrite
pnpm dlx bna-ui add button --overwrite
Preview what would be installed
pnpm dlx bna-ui add button --dry-run
Add components without confirmation
pnpm dlx bna-ui add button input --yes
Package managers
Pass a flag to force one:
--npm--yarn--pnpm--bun
Without a flag the CLI works it out, in this order:
packageManagerin yourcomponents.json.- How you invoked it —
npx,pnpm dlx,bunx. - Your project's lockfile or its
packageManagerfield. - npm.
The scaffold commands print which one they picked.
Why scaffolds pin a linker
Metro and React Native's autolinking both read node_modules off disk, so Expo
needs a real, flat one. Two package managers do not give it one by default, and
scaffolds ship the config that fixes each.
yarn
Yarn 2+ installs Plug'n'Play by default — a
.pnp.cjs resolver and no node_modules directory at all, which Metro cannot
read. Scaffolds ship:
nodeLinker: node-modulesYarn 1.x is flat already and ignores this file.
pnpm
Scaffolds ship an .npmrc and a pnpm-workspace.yaml that both pin pnpm to the
hoisted linker:
node-linker=hoistednodeLinker: hoistedExpo needs a flat node_modules — Metro resolves its own empty module out of
metro-config's require paths, and React Native's autolinking walks
node_modules by hand. Under pnpm's default isolated layout expo start fails
with Unable to resolve module …/metro-runtime/src/modules/empty-module.js.
Both files ship because pnpm 11 reads settings only from pnpm-workspace.yaml
while pnpm 10.15 and older read only .npmrc.
If you have a project scaffolded before this landed, add both files and
reinstall. Clear Metro's cache on the first run — switching an existing project
from the isolated layout to the hoisted one turns node_modules/react-native
from a symlink into a real directory, and a warm cache fails on the change with
TreeFS: Could not add directory node_modules/react-native:
rm -rf node_modules pnpm-lock.yaml
pnpm install
npx expo start --clearOn This Page
initOptionsconvexOptionssupabaseOptionsfirebaseOptionsaddOptionsWhere components come fromlistOptionssearchOptionsinfoOptionsmcpcomponents.jsonWhere files landAliasesExamplesInitialize a new projectInitialize with Convex backendInitialize with Supabase backendInitialize with Firebase backendInitialize using specific package managerSkip package installationAdd a button componentAdd multiple componentsAdd component with overwritePreview what would be installedAdd components without confirmationPackage managersWhy scaffolds pin a linkeryarnpnpm