Components Reference
Thirty-seven primitives in src/components/ui/, 84 components in total once compound parts are counted. Each is a folder with an index.ts and an exported tv() recipe. /examples/ui renders every one in every variant; the contract is in Components.
Used by real pages (13): accordion, badge, breadcrumb, button, card, input, nav, pagination, password, reveal, select, sheet, skeleton — plus dialog, reached through sheet. The rest ship for you to reach for.
Basics
| Primitive | Parts | JS |
|---|---|---|
button |
Button | — |
input |
Input | — |
label |
Label | — |
textarea |
Textarea | — |
badge |
Badge | — |
card |
Card, CardImage, CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter | — |
alert |
Alert | — |
separator |
Separator | — |
skeleton |
Skeleton | — |
avatar |
Avatar | — |
card is the compound worth knowing: four of Indexa’s seven card compositions build on it. skeleton uses Tailwind’s built-in animate-pulse rather than a catalog entry.
Disclosure and navigation
| Primitive | Parts | JS |
|---|---|---|
accordion |
Accordion, AccordionItem, AccordionTrigger, AccordionContent | — (<details>) |
tabs |
Tabs, TabsList, TabsTrigger, TabsContent | own script |
tooltip |
Tooltip | — (CSS only) |
breadcrumb |
Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator | — |
pagination |
Pagination, PaginationItem, PaginationLink, PaginationEllipsis | — |
nav |
Nav, NavItem, NavLink | — |
mega-menu |
MegaMenu, MegaMenuTrigger, MegaMenuPanel, MegaMenuItem | shared _popover.ts |
list |
List, ListItem | — |
progress |
Progress | — |
spinner |
Spinner | — |
PaginationLink reuses button’s recipe rather than defining a second one. MegaMenu is click-to-open only — hover triggers are hostile to touch and keyboard, and the file says so in a ponytail: note. Tabs degrades to all-panels-visible without JavaScript.
Overlays
| Primitive | Parts | JS |
|---|---|---|
dialog |
Dialog, DialogTrigger, DialogClose, DialogHeader, DialogTitle, DialogDescription, DialogFooter | shared _dialog.ts |
sheet |
Sheet (+ Dialog’s trigger/close/content parts) | shared _dialog.ts |
dropdown |
Dropdown, DropdownTrigger, DropdownMenu, DropdownItem | shared _popover.ts |
All three are native: dialog and sheet are modal <dialog> (a Sheet is a Dialog pinned to an edge by a side variant), dropdown is the Popover API, so its menu renders in the top layer and cannot be clipped. Escape, light-dismiss and focus return are the platform’s. The entry and exit transitions, the backdrop scrim and the modal scroll-lock live in _overlay.css as real @starting-style transitions that honour prefers-reduced-motion.
Form controls
| Primitive | Parts | JS |
|---|---|---|
select |
Select | — (native <select>) |
checkbox |
Checkbox | — |
radio |
Radio | — |
switch |
Switch | — |
slider |
Slider | — (native range) |
input-number |
InputNumber | own script |
toggle-count |
ToggleCount, ToggleCountValue | — (built on Switch) |
password |
PasswordInput, PasswordStrength | own scripts |
combobox |
ComboBox, ComboBoxOption | own script |
advanced-select |
AdvancedSelect | own script — requires JS |
searchbox |
Searchbox, SearchboxItem | own script |
checkbox, radio and switch are native inputs styled appearance-none with peer and :checked. PasswordStrength is a four-segment meter driven by the pure scorePassword, which has its own runnable check. AdvancedSelect is backed by a visually-hidden native <select> so it still submits, but it is the one primitive that does not work without JavaScript — the zero-JS alternative is select. Searchbox is a ⌘K palette reusing the Dialog shell.
Data and motion
| Primitive | Parts | JS |
|---|---|---|
table |
Table, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell, TableCaption | — |
marquee |
Marquee | — (CSS keyframes) |
reveal |
Reveal | — (native scroll timeline) |
table is styling only — sorting and data-grid behaviour are out of scope. marquee’s seamless loop works by shifting one full copy width plus one gap, which is why --marquee-gap has to match the flex gap; its keyframes live in tailwind-theme.css beside that variable. reveal is the one primitive about motion: an entrance animation on animation-timeline: view(), zero JavaScript, following useAnimations with motion-reduce:animate-none for the case the global guard cannot reach. Motion explains that pair.
The shared internals
Not primitives, and not importable as components — the modules with a leading underscore that the primitives share:
_dialog.ts is the one delegated controller for every dialog and sheet. _popover.ts places and manages every Popover-API menu, driving both Dropdown and MegaMenu. _field.ts is the shared field recipe behind the text inputs, select and the advanced controls. _listbox.ts holds filterByText, nextIndex and createActiveDescendant for the three filterable controls. _client.ts is onReady — the load plus astro:after-swap re-init contract every scripted primitive follows. _overlay.css is the overlay animation and scroll-lock layer. _Chevron.astro is the single disclosure chevron glyph, with rotation left to the call sites.
If you are adding a scripted primitive, use onReady rather than a bare DOMContentLoaded listener — under view transitions the second one only works until the first in-site navigation.