The components follow shadcn/ui's model of composing primitives from editable source, with the Base UI implementation selected in this workspace. A component is usually split into Root, Trigger, Content, Item, and related parts. The underlying primitive owns state and accessibility, while Tailwind classes and `data-slot` expose presentation.
| Text input | `input`, `textarea`, `input-group`, `input-otp` |
| Field structure | `field`, `label` |
| Boolean and single choice | `checkbox`, `switch`, `radio-group` |
| Range and progress | `slider`, `progress` |
| Options and commands | `native-select`, `select`, `combobox`, `command` |
| Dates | `calendar` |
Prefer `NativeSelect` for simple, mobile-friendly choices that do not need a custom popup. Choose `Combobox`, `Select`, or `Command` when the interaction needs search, custom items, or command behavior.
## Overlays and navigation {#overlays-and-navigation}
Dialog, Sheet, and Drawer expose controlled state and composable parts. Use `AlertDialog` for consequential destructive actions, `Tooltip` for brief descriptions, and `Popover` for an anchored panel containing interactive controls.
`Message` owns participant layout, alignment, and metadata; `Bubble` owns the message surface; `Attachment` expresses an upload lifecycle; and `MessageScroller` handles follow mode and jump controls. They are presentation primitives and do not own conversation data.
The chart module wraps Recharts containers, tooltips, legends, and style mappings without choosing an application data model. `DirectionProvider` re-exports Base UI's direction context; the page should still synchronize the HTML `dir` attribute.
import { SearchIcon, SettingsIcon } from "@workspace/ui/components/icon"
```
Components provide a default size to SVGs that do not have an explicit size class. Icon buttons still require an accessible name:
```tsx
<Button size="icon" aria-label="Search">
<SearchIcon aria-hidden="true" />
</Button>
```
Do not reintroduce `lucide-react` in new components. Register additional icons through `createIcon` in `components/icon.tsx` so the workspace keeps one icon path.