# BeeUI — full agent context > Expanded stable-API, setup, compatibility, and architecture-contract detail for coding agents. Companion to llms.txt (compact index), llms-components.txt (component inventory), and llms-patterns.txt (patterns). STATUS: BeeUI `0.86.2-rc.3` is public on npm under the opt-in `next` dist-tag (observed 2026-09-25T06:25:18.371Z). `latest` currently resolves to `0.86.2-rc.3` and lags `next` until the owner moves it for all four packages. Every release-candidate install should still use `@next` or pin the exact version — do not recommend an unqualified, untagged install, since `latest` lags `next` between an RC publication and the owner's move. `npm install @beemvp/beeui-ui@next @beemvp/beeui-core@next @beemvp/beeui-tokens@next` and `npx @beemvp/beeui-cli@next --help` are live, working registry commands today. The source-ownership CLI (`pnpm beeui add `) remains available from a repository checkout. See [docs/dist-tag-policy.md](docs/dist-tag-policy.md) for the full release/dist-tag mechanics. ## What BeeUI is BeeUI is a reusable, mobile-first React Native UI foundation for long-lived client apps. The public component API stops at `@beemvp/beeui-ui`; applications should not need to know the styling engine. Web support is additive and native ergonomics remain first-class. See [docs/architecture.md](docs/architecture.md). ## Packages (public on npm under `next`, one lockstep version) - `@beemvp/beeui-core` v0.86.2-rc.3 — Engine-neutral utilities (class-name merging, anchored-overlay geometry) shared by @beemvp/beeui-ui. No React, React Native, or Expo dependency. [public on npm under `next` (last observed 0.86.2-rc.3)] - `@beemvp/beeui-tokens` v0.86.2-rc.3 — BeeUI's design-token system: semantic color/spacing/typography/motion contracts and the canonical Uniwind/Tailwind theme CSS. [public on npm under `next` (last observed 0.86.2-rc.3)] - `@beemvp/beeui-ui` v0.86.2-rc.3 — Typed React Native + Web components built on @beemvp/beeui-core and @beemvp/beeui-tokens, styled through Uniwind/Tailwind. [public on npm under `next` (last observed 0.86.2-rc.3)] `@beemvp/beeui-core`, `@beemvp/beeui-tokens`, and `@beemvp/beeui-ui` share one lockstep version and are released together (ADR-011 D6). All three are public on npm under the `next` dist-tag (last observed at `0.86.2-rc.3`; during the prerelease line `latest` follows the newest complete, verified RC only after the owner moves it — see docs/dist-tag-policy.md); `exports` maps ship dual ESM+CJS with `.d.ts`, a `react-native` condition for Metro, `browser`/`default` for Web, and `@beemvp/beeui-tokens/theme.css` for the Web theme. ## Consumption models 1. Centralized packages (public RC, opt in with `@next`): `npm i @beemvp/beeui-ui@next` pulls `@beemvp/beeui-core` + `@beemvp/beeui-tokens`; import components from `@beemvp/beeui-ui`; wire Web theme with `@import '@beemvp/beeui-tokens/theme.css'`. Pin `@0.86.2-rc.3` for an immutable version in CI. 2. Source ownership (works today, repo-local): `pnpm beeui add ` copies component source in-tree and rewrites `@beemvp/beeui-core` imports via `rewrite-beeui-core-cn` / `rewrite-beeui-core-module`. Run `pnpm beeui list` for the canonical component list (generated from registry/registry.json). Published CLI: `@beemvp/beeui-cli` (binary `beeui`), `npx @beemvp/beeui-cli@next add ` — never `npx beeui` (the unscoped name is an npm tombstone; see [docs/distribution-names.md](docs/distribution-names.md)). See [docs/decisions/011-distribution-architecture.md](docs/decisions/011-distribution-architecture.md) and [docs/registry-cli.md](docs/registry-cli.md). ### Consuming the packages before release (pnpm pack tarballs) The centralized model above is a target, but a new, standalone external app can already consume it **today** without npm — as local tarballs, the same package boundary CI's `scripts/verify-web-consumer.sh` / `scripts/verify-bare-consumer.sh` and the checked-in starters use (never a `workspace:*` link or a hand-copied `dist/`). Steps: (1) build the packages once from the repo root (`pnpm build`); (2) pack `@beemvp/beeui-core`, `@beemvp/beeui-tokens`, and `@beemvp/beeui-ui` into `*.tgz` files — the starters do this with [examples/scripts/pack-beeui-packages.mjs](examples/scripts/pack-beeui-packages.mjs), which runs `pnpm pack` per package; (3) install the tarballs into the consumer with `npm install --save-exact `, which pins them as `"@beemvp/beeui-ui": "file:….tgz"` dependencies. This resolves the real package `exports` maps and the Web theme CSS exactly as a published install would, so no fictional npm entry is needed. Worked, buildable reference: [examples/web-consumer](examples/web-consumer) and [examples/README.md](examples/README.md). ## Quick start (repository) ```bash corepack enable pnpm install --frozen-lockfile pnpm showcase # then press i (iOS), a (Android), or w (Web) ``` Verification: `pnpm check` (typecheck + tests), `pnpm release:verify` (package gate), `pnpm --dir apps/visual-regression test` (browser QA). See [README.md](README.md). ## Provider and safe-area setup Wrap the app root in `BeeUIProvider` (installs safe-area measurement, the Toast runtime, and the shared anchored-overlay runtime). `SafeArea` assigns explicit `top`/`bottom`/`left`/`right` edge ownership; `Screen`, `AppHeader`, and `BottomActionBar` never add insets themselves. See [apps/docs/src/content/docs/start/provider-safe-area.md](apps/docs/src/content/docs/start/provider-safe-area.md). **`Sheet` on native requires `SheetProvider`.** Mount BeeUI's public `SheetProvider` directly below `BeeUIProvider`, above the rest of the app: `BeeUIProvider > SheetProvider > app`. On native, `SheetProvider` installs `GestureHandlerRootView` and gorhom's `BottomSheetModalProvider` itself — do not also mount an outer `GestureHandlerRootView`/`BottomSheetModalProvider` (the rc.1 wiring); remove that outer provider when upgrading. `SheetProvider` deliberately does not reuse an already-present outer gorhom provider (dev-time warning if one is detected). `SheetContent` only sees React contexts mounted above `SheetProvider`; app-wide providers (query client, i18n, navigation, app stores) belong above `SheetProvider`, and a screen-scoped provider that a Sheet's content still needs must be passed through `SheetContent bridgeContexts`. Web and the RN `Modal` fallback: `SheetProvider` is a pass-through. See [apps/docs/src/content/docs/components/sheet.md](apps/docs/src/content/docs/components/sheet.md) and [ADR-006](docs/decisions/006-sheet-gesture-engine.md). ## Web bundling (Vite + react-native-web) `@import '@beemvp/beeui-tokens/theme.css'` supplies the semantic tokens but is not, by itself, a Web build. A from-scratch Vite + react-native-web app needs a specific plugin stack and a Tailwind/Uniwind CSS entry; get it wrong and the app either fails to resolve `react-native` or builds **unstyled**. The tested stack: - `vite.config.ts` — three plugins, in this order: `rnw()` from `vite-plugin-rnw` (resolves `react-native` → `react-native-web`), `tailwindcss()` from `@tailwindcss/vite`, and `uniwind()` from `uniwind/vite` (passed `cssEntryFile` + `dtsFile`). - A CSS entry (e.g. `src/global.css`) imported once from the app entry, declaring in order: ```css @import 'tailwindcss'; @import 'uniwind'; @import '@beemvp/beeui-tokens/theme.css'; @source '../node_modules/@beemvp/beeui-core/src'; @source '../node_modules/@beemvp/beeui-ui/src'; ``` The `@source` globs are **required**: Tailwind/Uniwind only emit utility classes they can statically discover, and BeeUI's classes live inside the installed packages' `src`. Omit them and the build succeeds but ships with no BeeUI styling. Pinned/tested versions for every dependency in this stack are in [docs/compatibility-matrix.md](docs/compatibility-matrix.md); the complete buildable reference is [examples/web-consumer](examples/web-consumer) ([vite.config.ts](examples/web-consumer/vite.config.ts), [src/global.css](examples/web-consumer/src/global.css)). Web support boundaries: [docs/web-support-contract.md](docs/web-support-contract.md). ## Runtime theme switching (app-owned system/light/dark) Brand and density live in tokens (`@import` the theme, ADR-001), but the **app-level** switch between light, dark and system at runtime is owned by the application and driven through Uniwind — not a BeeUI component. The application owns exactly one preference state (BeeUI/Uniwind does not store or persist it) with three values: `type ThemePreference = 'system' | 'light' | 'dark'`, passed to `Uniwind.setTheme(preference)`. `setTheme('light')`/`setTheme('dark')` pin the app to that runtime theme regardless of what the OS/browser reports afterward; `setTheme('system')` is meant to release that pin and resume following the platform/browser color scheme. `useUniwind()` reads the current `{ theme }` (and `hasAdaptiveThemes`) so the app re-renders. The valid runtime-theme names are exported from `@beemvp/beeui-tokens` as `beeRuntimeThemeNames` (`light`, `dark`, `violet-light`, `violet-dark`). **Known gap, verified against `@beemvp/beeui-*@0.86.2-rc.1` with Uniwind `1.10.1`:** after an explicit `setTheme('light')`/`setTheme('dark')`, a later `setTheme('system')` type-checks and does not throw, but the app can stay pinned to the last explicit theme — it does not reliably resume following the OS/browser scheme. Treat this as an open behavior gap in the pinned Uniwind version, not a documented contract, and resolve "system" yourself: read `Appearance`/`useColorScheme` (native) or `window.matchMedia('(prefers-color-scheme: dark)')` (Web) to resolve `'system'` to `'light'`/`'dark'` before calling `Uniwind.setTheme`, and re-run that resolution whenever the OS/browser scheme changes while the preference is `'system'`. Full pattern with a working `useResolvedSystemScheme`/`applyThemePreference` implementation: [apps/docs/src/content/docs/theming/index.md](apps/docs/src/content/docs/theming/index.md). This three-state preference is a single small piece of app state deciding *which* value BeeUI's existing theme runtime uses — not a second theme authority, and a different concern from `BeeThemeScope`, which themes one subtree independently of the app-wide preference (a public `@beemvp/beeui-ui` export). See [docs/theming.md](docs/theming.md) and the cookbook's Recipe F in [docs/ai-agent-cookbook.md](docs/ai-agent-cookbook.md). ## Architecture invariants (do not violate) - Stable behavior/semantic/variant APIs are independent of Uniwind, Expo, routers, storage, networking, and business logic. - Components consume semantic tokens (`bg-primary`, `text-foreground`, `border-border`); never literal brand colors. Every semantic token exists in every theme. - `className` is an optional current-engine escape hatch, not a portability guarantee; engine-only bridge props stay internal. - No duplicate theme, overlay, focus, direction, or state authority. One application-root overlay runtime; nested providers reuse it. - Tailwind/Uniwind utilities must be statically discoverable — never construct `bg-${x}` dynamically. - Controlled primitives (Checkbox, Radio, RadioGroup, Switch, Tabs, SegmentedControl, and others) require their change callback; enabled usage without it warns in development. - Accessibility, RTL/logical direction, large text, high contrast, and reduced motion are part of component correctness. - Never nest one pressable inside another. A `*Trigger` (DropdownMenuTrigger, PopoverTrigger, TooltipTrigger, SheetTrigger, DialogTrigger, AlertDialogTrigger) is itself a full Button-shaped pressable — put icon/label children directly inside it, do not wrap an IconButton/Avatar in one. The same rule applies wherever a family exposes a pressable slot: `ListItem`'s `trailing` (an IconButton there is still a second nested pressable), `SettingsItem` composed with `AlertDialogTrigger`, and any other pressable-inside-pressable composition. On Web this renders one interactive element inside another, which React flags as invalid DOM nesting; use `variant="ghost"` on the outer pressable instead of nesting a second one. See [AGENTS.md](AGENTS.md) and [docs/architecture.md](docs/architecture.md). ## Non-goals (explicit) BeeUI does not build or bundle a styling compiler, router, backend, state library, form framework, chart framework, data-grid, or virtualization engine to match another ecosystem's feature list. It owns no fetching, navigation, auth, or persistence. Timezone/business-calendar rules stay with the application (ADR-008). Table is a primitive family, not a data grid (ADR-007). Select has no Sheet mode or virtualization for 1.0 (ADR-010). ## Overlay model (summary) - Modal-class `Dialog`/`AlertDialog` use React Native core `Modal`. `DialogContent` defaults to `overFullScreen` (transparent); `fullScreen`/`pageSheet`/`formSheet` are non-transparent so RN honors the presentation. - Anchored `Popover`/`DropdownMenu`/`Select`/`Tooltip` share one non-modal geometry/runtime/portal/dismiss kernel installed by `BeeUIProvider`. - `Sheet` on native requires BeeUI's public `SheetProvider` mounted below `BeeUIProvider` (`BeeUIProvider > SheetProvider > app`); it installs `GestureHandlerRootView` + gorhom's `BottomSheetModalProvider` itself, so do not also mount an outer one. See "Provider and safe-area setup" above. - Portal transport: Web `ReactDOM.createPortal`; native New Architecture `react-native-teleport`; defensive legacy fallback (does not preserve consumer context). - Global dismissal targets the deepest active scope via semantic depth, independent of React effect order. Native measurement uses latest-request-wins generation guards. - `Toast` is a separate transient-notification runtime (not modal, not anchored). See [docs/anchored-overlays.md](docs/anchored-overlays.md). ## Platform / compatibility boundaries - Targets React Native first: Expo, Expo prebuild/dev builds, bare RN, and documented RN Web. Expo-specific APIs live in apps/adapters, never core packages. - Pinned/tested versions (React, React Native, Expo SDK, react-native-web, Tailwind, Uniwind, safe-area-context, teleport) are the authority in [docs/compatibility-matrix.md](docs/compatibility-matrix.md); Web support boundaries in [docs/web-support-contract.md](docs/web-support-contract.md). - iOS `pageSheet`/`formSheet` presentation is EXPERIMENTAL for 1.0 (compile + deterministic evidence only; live placement/swipe is a device gate). Compilation/browser evidence never proves full native runtime behavior. ## Accessibility Accessibility roles/names/states/focus/keyboard are component correctness, not an add-on. Web gets real focus traps (Dialog/Sheet), listbox/menu keyboard semantics, and `aria-*` relationships; native uses RN semantic roles and merged hints where no equivalent role exists. VoiceOver/TalkBack claims require device evidence. See [docs/accessibility-contract.md](docs/accessibility-contract.md). ## Architecture decision records - [ADR-001 styling-engine](docs/decisions/001-styling-engine.md): Uniwind + Tailwind v4 as the current, replaceable styling engine behind stable APIs. - [ADR-002 overlay-behavior](docs/decisions/002-overlay-behavior.md): Modal-class vs anchored overlays use different behavior primitives. - [ADR-003 native-measurement-timeout](docs/decisions/003-native-measurement-timeout.md): Bounded native measurement completion and deterministic fallback. - [ADR-004 direction-architecture](docs/decisions/004-direction-architecture.md): One stateless LTR/RTL resolver; BeeUI reads ambient direction, never writes it. - [ADR-005 tooltip-contract](docs/decisions/005-tooltip-contract.md): Tooltip is a non-interactive contextual disclosure, not a click menu. - [ADR-006 sheet-gesture-engine](docs/decisions/006-sheet-gesture-engine.md): Sheet: @gorhom/bottom-sheet on native, BeeUI Web overlay on Web; no drag-parity claim. - [ADR-007 table-datatable-architecture](docs/decisions/007-table-datatable-architecture.md): Table is a composable primitive family, not a data-driven grid. - [ADR-008 datetime-architecture](docs/decisions/008-datetime-architecture.md): Timezone-free, Intl-driven, single-date-selection value contracts. - [ADR-009 slider-1-0-decision](docs/decisions/009-slider-1-0-decision.md): Slider scope decision for 1.0. - [ADR-010 select-presentation-1-0-decision](docs/decisions/010-select-presentation-1-0-decision.md): Select presentation scope for 1.0 (no Sheet mode / virtualization). - [ADR-011 distribution-architecture](docs/decisions/011-distribution-architecture.md): Public distribution model: three scoped packages + source-ownership CLI, public on npm under `next` (last observed at 0.86.2-rc.3). ## Registry / source ownership [registry/registry.json](registry/registry.json) is the machine-readable source of 74 items: 63 public components, 1 public theme, and internal utilities (core-cn, core-overlay, field-context, form-group-context, overlay-runtime, sheet-context-bridge, theme-scope-bridge, toast-runtime-bridge, use-direction, use-required-callback-warning). Each item declares source files, transforms, registry dependencies, and peer dependencies. Component-to-symbol mapping is verified against [packages/ui/src/index.ts](packages/ui/src/index.ts) at generation time. ## Documentation map - AI-agent contract + prompt cookbook: [docs/ai-agent-cookbook.md](docs/ai-agent-cookbook.md) - Authority index: [docs/README.md](docs/README.md) - Start: [Expo](apps/docs/src/content/docs/start/expo.md) · [bare RN](apps/docs/src/content/docs/start/bare-react-native.md) · [Web](apps/docs/src/content/docs/start/web.md) - CLI: [apps/docs/src/content/docs/guides/cli-source-ownership.md](apps/docs/src/content/docs/guides/cli-source-ownership.md) - Components site: [apps/docs/src/content/docs/components/index.md](apps/docs/src/content/docs/components/index.md) (deep dives: [Table guide](apps/docs/src/content/docs/guides/table.md), [Dates and times guide](apps/docs/src/content/docs/guides/date-time.md)) - Performance: methodology [docs/benchmark-harness.md](docs/benchmark-harness.md) · baseline report [docs/performance-baseline-report.md](docs/performance-baseline-report.md) · package/bundle footprint [docs/bundle-footprint-baseline.md](docs/bundle-footprint-baseline.md) · docs site [apps/docs/src/content/docs/performance/index.md](apps/docs/src/content/docs/performance/index.md) - Release policy: [docs/release.md](docs/release.md) · Changelog: [CHANGELOG.md](CHANGELOG.md) · License: [LICENSE](LICENSE) (MIT) Generated by scripts/generate-llms-txt.mjs from registry/registry.json, packages/ui/src/index.ts, packages/*/package.json, and docs/dist-tag-policy.md. Do not edit by hand; run `pnpm llms:generate`.