Components
The platform ships parallel component libraries, intentionally shaped so a control’s API is recognisable across stacks:
- Web — bits-ui (headless primitives) + custom wrappers under
apps/svelte-web/src/lib/components/ui/. ~49 directories, ~213.sveltefiles. - Native mobile — each app (
apps/ios-user+apps/android/app-user, and the agent apps) ships a hand-built, lockstep primitive library so feature code never re-rolls UI. The authoritative list lives on Conventions → Mobile (Native).
For framework rules — kebab-case filenames (web) vs PascalCase (native), no hand-rolled buttons, generated design tokens over hardcoded color — see Conventions → Web and Conventions → Mobile (Native).
Web primitives
Section titled “Web primitives”Organized by tier (per the team’s internal style guide). All bits-ui wrappers live under apps/svelte-web/src/lib/components/ui/{name}/; higher-level domain compositions live under apps/svelte-web/src/lib/components/{feature}/.
Tier 1 — base controls and overlays
Section titled “Tier 1 — base controls and overlays”| Component | Source dir | Purpose |
|---|---|---|
Button | ui/button/ | bits-ui Button + size / variant slots |
Input | ui/input/ | Text input wrapper with focus ring tokens |
Label | ui/label/ | Form label with required / optional indicator slots |
Card | ui/card/ | Card container with Header / Title / Description / Content / Footer subparts |
Dialog | ui/dialog/ | Modal overlay; the “destructive confirm” pattern lives here |
Sheet | ui/sheet/ | Side-anchored panel (left / right / top / bottom) |
Drawer | ui/drawer/ | Vaul-svelte mobile-first sheet with snap points |
Tabs | ui/tabs/ | Tabbed pages; tab list + tab triggers + tab panels |
Accordion | ui/accordion/ | Collapsible disclosure groups |
Select | ui/select/ | Single-select dropdown (Combobox for filtering) |
Combobox | ui/combobox/ | Filtered Select with text search |
Switch | ui/switch/ | Boolean toggle |
Toggle | ui/toggle/ | Stateful pressed button |
Checkbox | ui/checkbox/ | Tri-state checkbox |
RadioGroup | ui/radio-group/ | Single-pick radios |
DatePicker / Calendar | ui/date-picker/ + ui/calendar/ | Date input + month grid |
Popover | ui/popover/ | Anchored floating panel |
Tooltip | ui/tooltip/ | Hover-triggered label |
DropdownMenu | ui/dropdown-menu/ | Menu with submenus, separators, checkboxes |
Separator | ui/separator/ | Horizontal or vertical rule |
ScrollArea | ui/scroll-area/ | Custom scrollbar wrapping native overflow |
Command | ui/command/ | Cmdk-style palette (used in headers + admin tools) |
NavigationMenu | ui/navigation-menu/ | Top-level nav primitive |
Tier 2 — forms
Section titled “Tier 2 — forms”| Component | Source dir | Purpose |
|---|---|---|
Field | ui/field/ | Label + Input + error container (standalone — no Formsnap dep) |
Form | via Formsnap | superforms + Zod integration; emit <Form.Field> per input |
InputGroup | ui/input-group/ | Prefix / suffix slots around an Input (currency symbol, unit) |
InputOTP | ui/input-otp/ | 6-digit code split inputs with auto-advance |
Textarea | ui/textarea/ | Multi-line input |
NumberStepper | ui/number-stepper/ | +/− buttons around a numeric value |
NumericInput | ui/numeric-input/ | Numeric-only Input with comma thousands formatting |
PhoneInput | ui/phone-input/ | MX-default international phone field |
TimeRangeField | ui/time-range-field/ | Start + end time picker, used in tour scheduling |
Data display
Section titled “Data display”| Component | Source dir | Purpose |
|---|---|---|
Table | ui/table/ | Header / body / row primitives |
DataTable | via TanStack Svelte Table | Column defs + filtering + pagination |
Carousel | ui/carousel/ | Embla-svelte image carousel (property galleries) |
Alert | ui/alert/ | Inline info / warning / error banner |
Progress | ui/progress/ | Linear progress bar |
Badge | ui/badge/ | Status pill (uses status-* tokens) |
Feedback
Section titled “Feedback”| Component | Source dir | Purpose |
|---|---|---|
Spinner | ui/spinner/ | Loading indicator |
Skeleton | ui/skeleton/ | Placeholder rectangles |
Toaster / Toast | via svelte-sonner | Bottom-anchored toast; integrate via <Toaster /> at root |
EmptyState | ui/empty-state/ | Icon + heading + body + CTA (used across dashboard / portal / mobile) |
StatCard | ui/stat-card/ | KPI tile with label + value + delta |
Navigation
Section titled “Navigation”| Component | Source dir | Purpose |
|---|---|---|
LaunchpadTile | ui/launchpad-tile/ | 7 variants — Counter, Link, KPI, Status, Shortcut, Grouped, default. Shared base styles; used for hub / dashboard navigation. |
ButtonGroup | ui/button-group/ | Joined buttons (segmented controls) |
Command palette | ui/command/ | Global search palette (⌘K) |
Native mobile primitives
Section titled “Native mobile primitives”Each native app ships its own hand-built primitive library (matching API + visuals on iOS and Android) rather than a shared package. Colors come from the generated token files via @Environment(\.tokens) (iOS) / LocalTokens.current (Android) — never hardcoded hex — and the rule is no hand-rolled buttons.
The shared set includes: PrimaryButton / SecondaryButton, ListRow, SwitchRow, CheckboxRow, SegmentedControl (single + multi select), SelectablePill / DismissibleChip, Avatar, StatusBadge, Toast (via ToastCenter), EmptyState, Skeleton, text Inputs, and PickerSheet. Property cards compose platform-native card/image/specs views with the favorite heart, multi-unit pills, and price-drop badge.
The authoritative list — and the mobile-ui-audit skill that flags violations — lives on Conventions → Mobile (Native).
Cross-reference
Section titled “Cross-reference”For the runtime rules that govern how these components are used:
- Conventions → Web — form-action template, Formsnap integration, auth gates, error handling.
- Conventions → Mobile (Native) — PascalCase filenames, generated design tokens (no hardcoded color), cookie auth, the shared primitive list.
- Design → Tokens — the color, typography, spacing, radius, and shadow values these components consume.
- Design → Principles — the design intent (property-first hierarchy, status taxonomy, dark mode strategy).