Theme keys
Theme keys are the per-slot Tailwind class definitions shipped by @vueda/theme/vueda-tailwind. Underscore-prefixed entries are composition primitives consumed by leaf keys via composes.
controls
| Component | Kind | Slots | Description |
|---|---|---|---|
| _ButtonBase | primitive | 1 | The shared button shell: inline-flex layout, 2px control radius, sm font-medium type, default 16px icon sizing, focus-visible ring, and the system-wide disabled treatment. Height and horizontal padding are omitted; the leaf picks a tier from base.css § Control sizing. |
| _ButtonDefault | primitive | 1 | The --primary CTA fill: solid primary background, primary-foreground text. Hover and active swap the fill to the --primary-hover / --primary-active lightness steps (darker in light mode, lighter in dark) so the state change clears the glance-detection threshold rather than washing out the way the old /90 alpha fade did. Pair sparingly with neutral pressed-state recipes like Toggle.root so a CTA and an active toggle do not compete. |
| _ButtonDestructive | primitive | 1 | The --destructive fill: solid destructive background in light mode, 60%-mix in dark so the chip stays legible against --background at rest, destructive-foreground text, and a destructive-tinted focus outline. Hover and active swap to the --destructive-hover / --destructive-active lightness steps (darker in light mode, lighter in dark). Reserve for actions that delete user data or are otherwise irreversible; menu / list destructive items use a colour-only recipe. |
| _ButtonOutline | primitive | 1 | The neutral-chip recipe: DPR-aware hairline at --border-strong that darkens to --foreground on hover (a chip that still reads as a control without outweighing the one filled action beside it), --background fill, shadow-vueda-control micro-shadow, and an --accent hover swap with an --accent-active pressed step. The hairline paints as an inset shadow rather than a layout border, so outlined buttons match fill-button intrinsic width while using the same chromatic-fringing mitigation as inputs. Hover / active use the mode-aware --accent tokens in both light and dark, so the lightness step is identical in either mode; only the rest fill differs (dark mode keeps the input-tint convention, bg-input/30, so an outlined chip reads input-like at rest while keeping its stronger edge). The earlier dark-mode bg-input/50 hover topped out near the rest lightness because --input is itself dark, leaving the smaller sizes with no perceptible state change. Reused by chip-shaped leaves that want the button shape without a fill, including FileUpload.trigger and the calendar prev / next buttons, so the hover and pressed steps reach those surfaces too. |
| _ButtonSecondary | primitive | 1 | The --secondary surface fill: solid secondary background, secondary-foreground text. Hover and active swap to the --secondary-hover / --secondary-active lightness steps (darker in light mode, lighter in dark); the previous /80 alpha hover was near-invisible because secondary sits almost on the page surface. Use for actions that sit beside a CTA without stealing it; a row of secondary buttons reads as a control cluster rather than a set of competing CTAs. |
| _ButtonGhost | primitive | 1 | The transparent-at-rest recipe: no fill or edge until hover, when --accent paints the background, with an --accent-active pressed step (dark mode: half-strength accent/50 hover, full accent active). Shared by CalendarCellTrigger.root and RangeCalendarCellTrigger.root so day buttons in a calendar grid keep one consistent hover and press affordance; dark-mode hover is half-strength accent so the day button does not over-saturate the popover surface. |
| _ButtonLink | primitive | 1 | The inline-text recipe: --primary text with a 4px underline offset that appears on hover only; active deepens the text to --primary-active. The link emphasis of Button also drops the control height and horizontal padding so the affordance does not break surrounding line metrics. |
| _ButtonPrimaryOutline | primitive | 1 | The primary neutral-chip recipe: a DPR-aware --primary hairline and --primary text over the --background fill (dark mode keeps the outline-family bg-input/30 rest tint), with the shadow-vueda-control micro-shadow. The inset hairline avoids layout-width drift against fill buttons and uses the same saturated-edge fringing mitigation as inputs. Hover and active wash a low-alpha --primary tint behind the label (/10 then /15). The secondary-CTA treatment: it reads as accented without the full weight of a filled _ButtonDefault, so it can sit beside the primary fill as the "other" emphasized action. |
| _ButtonDestructiveOutline | primitive | 1 | The destructive neutral-chip recipe: a DPR-aware --destructive hairline and --destructive text over the --background fill (dark mode keeps the outline-family bg-input/30 rest tint), with the shadow-vueda-control micro-shadow. The inset hairline avoids layout-width drift against fill buttons and uses the same saturated-edge fringing mitigation as inputs. Hover and active wash a low-alpha --destructive tint behind the label (/10 then /15) so the chip warms toward danger on interaction without becoming a filled destructive CTA, and focus swaps to the destructive outline. Use for a reversible-but-cautionary action that should not carry the weight of a filled _ButtonDestructive (a low-emphasis delete in a toolbar or row). |
| _ButtonPrimaryGhost | primitive | 1 | The transparent-at-rest primary recipe: --primary text with no fill or edge until hover, when a low-alpha --primary tint paints the background (/10 hover, /15 active). The lowest-weight accented affordance, for an emphasized action inside a dense cluster where an outline or fill would be too heavy. |
| _ButtonDestructiveGhost | primitive | 1 | The transparent-at-rest destructive recipe: --destructive text with no fill or edge until hover, when a low-alpha --destructive tint paints the background (/10 hover, /15 active) and focus swaps to the destructive outline. The lowest-weight destructive affordance, for a cautionary action inside a dense cluster (a row's delete glyph, a menu-adjacent strip) where even an outlined chip would be too heavy. |
| _ButtonNeutralLink | primitive | 1 | The neutral inline-text recipe: --foreground text with a 4px underline offset that appears on hover only; active eases the label to 70% opacity. Unlike _ButtonLink, it does not tint the text with --primary, so a row of quiet text actions does not spread the earned accent across every secondary affordance. The link emphasis of Button also drops the control height and horizontal padding. |
| _ButtonDestructiveLink | primitive | 1 | The destructive inline-text recipe: --destructive text with a 4px underline offset that appears on hover only; active deepens the label to --destructive-active. The text-weight counterpart to _ButtonDestructive, for a cautionary action that must read inline with prose rather than as a control. |
| Button | key | 1 | The pressable root. Composes _ButtonBase.root plus the _Button* primitive for the resolved (tone, emphasis) cell (see controls/button/buttonVariant.js), then layers the per-size height / padding pair from base.css § Control sizing (or size-vueda-control* for icon-only sizes). The link emphasis skips the control-height block and goes inline. The data-state=cooldown state (set by the component while a one-shot action is recovering) mutes the label to --muted-foreground and suppresses hover so a recently-clicked button reads as "wait" without changing layout. |
| ButtonGroup | key | 1 | The segmented-cluster shell. Strips inner radii between adjacent children so a row (or column when orientation is vertical) of buttons, inputs, and Select triggers reads as one slab. Outline buttons use DPR-aware inset hairlines rather than layout borders, so adjacent outline buttons overlap by exactly --vueda-hairline-width to share one visible seam. Focus z-index promotion keeps the focus ring from being clipped by neighbours. Nested ButtonGroup children retain an 8px gap. The icon-only-stays-seamless / text-or-mixed-keeps-seams rule is applied by the component, not this slot. |
| ButtonGroupSeparator | key | 1 | The explicit divider used inside a ButtonGroup when the segmented cluster needs a visible split between text segments. Uses the --input token so the divider matches the surrounding hairline color in both modes, and stretches to the group's cross-axis. |
| ButtonGroupText | key | 1 | The static-label chip used to join readable copy ("of", "to", a unit suffix) into a ButtonGroup. Wears the button shape (2px control radius, hairline edge, shadow-vueda-control) but sits on --muted so it does not read as pressable; padding picks 16px to match the default button's px-vueda-control-px baseline. |
| Toggle | key | 1 | The on/off button shell. Reads as a Button shape (control radius, text-sm font-medium, 16px icon) but the pressed state (data-state=on) paints --accent instead of --primary so a pressed toggle does not compete with a CTA on the same surface. Two variants (default, outline) and three size tiers ride the shared h-vueda-control* scale; the outline variant wears the same hairline-border-strong edge, darkening to hairline-foreground on hover, as _ButtonOutline.root (an inset box-shadow, not a layout border, so it DPR-tracks and matches intrinsic width), and min-w-vueda-control* keeps a single-icon toggle square. |
| ToggleGroup | key | 1 | The row layout for a set of ToggleGroupItem.root children. The --gap custom property is driven by the consumer's spacing prop, which lets the same group render as a gapped row or (at spacing=0) as a segmented control where child items drop their outer radii and shared borders. The group/toggle-group Tailwind group label lets items react to group-level state. |
| ToggleGroupItem | key | 1 | The individual item inside a ToggleGroup. Mirrors the Toggle.root recipe (same variants, sizes, and accent-pressed treatment) and adds segmented behaviour: when the host group sets data-spacing=0, items drop their per-item radius and shadow and re-add them on the first and last child so the cluster reads as one slab. min-w-0 shrink-0 px-3 overrides the Toggle minimum width so a label-bearing item grows to its content rather than staying square. |
| FileUpload | key | 3 | The outer container. In inline-trigger mode this is a tight flex column wrapping the picker button plus optional helper text; in dropzone mode it grows into a dashed-border target (2px input-coloured dashes, 6 spacing pad, large radius) that highlights with a primary-tinted fill when dragging. The disabled state dims the whole region and switches the cursor; the inner trigger still picks up its own disabled treatment from _ButtonBase.root. |
| Input | key | 1 | The single-line input shell and the reference recipe for the input-shaped family. Hairline border with the system focus-ring contract, control-height tier from base.css § Control sizing, and the cross-cutting aria-invalid swap that paints --destructive on the border and ring. Read-only and dark-mode states follow the shared input conventions; the file-picker variant (<input type=file>) inherits file: classes so a bare file input reads as the same chip family as a button. |
| Textarea | key | 1 | The multi-line counterpart to Input.root. Same hairline + focus + aria-invalid recipe; grows vertically via field-sizing: content so the field expands with the typed text rather than holding a fixed min-height. Horizontal padding moves to px-3 py-2 (both axes) because a textarea's content box is two-dimensional. |
| InputGroup | key | 1 | The shell that joins an input (or textarea) with one or more addons (icon, button, kbd, helper line) into a single bordered chip. The group, not its children, owns the hairline and focus ring: child controls strip their own chrome (see InputGroupInput / InputGroupTextarea) and the group reacts to focus-visible on any [data-slot=input-group-control] and to aria-invalid on any tagged child via :has(...) selectors. Inline addons (align=inline-start / inline-end) stay on a single row at h-vueda-control; block addons (align=block-start / block-end) stack and flip the row to flex-col with auto height, so the same shell supports left/right glyphs and top/bottom helper rows. |
| InputGroupAddon | key | 1 | The addon slot inside an InputGroup.root. align picks one of four placements: inline-start / inline-end for icon, kbd, or button content flush against the input edge, and block-start / block-end for helper-text rows stacked above or below the input. Negative-margin hooks (has-[>button]:ml-[-0.45rem], has-[>kbd]:ml-[-0.35rem]) tighten interior padding when the addon hosts a button or kbd so the addon does not visually balloon. Inherits --muted-foreground text so the addon reads as chrome, not as content; dimmed in lockstep with the group when the host carries data-disabled=true. |
| InputGroupInput | key | 1 | The text-input child inside an InputGroup.root. Strips its own border, shadow, and focus ring so the surrounding group owns the chrome; flexes to fill the remaining row, and overrides the standalone Input dark-mode tint with dark:bg-transparent so the group's tint is the only one painted. The focus reset needs focus-visible:!shadow-none: Input.root paints its ring with focus-visible:focus-ring-shadow, whose variant selector outranks a plain shadow-none, so without it the input draws a second ring inside the group's. |
| InputGroupTextarea | key | 1 | The textarea child inside an InputGroup.root. Same chrome-strip recipe as InputGroupInput.root plus resize-none so the textarea grows with content rather than offering a corner drag handle that would fight the group's shared shell. |
| InputGroupText | key | 1 | The inline-text addon inside an InputGroup.root: helper labels, prefix / suffix copy, unit markers. Renders at sm size on --muted-foreground with 16px icons so the addon reads as chrome rather than as input content. |
| InputGroupButton | key | 1 | Pressable addon inside an InputGroup.root. Sized smaller than a standalone Button.root (xs, sm, plus icon-xs / icon-sm) so the button fits inside the input shell without breaking the row's h-vueda-control baseline. Shadow is suppressed because the group already carries shadow-vueda-control; an inset button drawing its own shadow would double-paint at the addon edge. The xs and icon-xs tiers use a tighter rounded-[calc(var(--radius)-5px)] so a 24px button reads as a chip inside a 32px shell rather than a miniature slab. |
| InputOTP | key | 1 | The container for a row of fixed-width character slots. Owns the focus-ring contract for the active slot: a single focus-ring paints around whichever slot carries data-active=true (and swaps to destructive on aria-invalid), rather than each slot drawing its own ring. This keeps one ring sweeping across the row as the cursor advances. |
| InputOTPGroup | key | 1 | A contiguous run of InputOTPSlot.root cells (e.g. the three digits before and after a - in a 3-3 split code). Pure flex row; the visual joining comes from the slots themselves overlapping their hairlines, so a group is just a layout marker that separates one run from the next when a code is split. |
| InputOTPSlot | key | 1 | A single character cell. Borders use --input at the border-hairline width, and every non-first slot pulls left by exactly --vueda-hairline-width so adjacent slots overlap one device pixel and read as one painted line rather than doubling at the seam. The active slot promotes z-10 and swaps to border-ring so the run's active position outlines cleanly above its neighbours; aria-invalid swaps the border to --destructive on the same rule. First / last children round only their outer corners so the run reads as one chip. |
| NativeSelect | key | 1 | The native <select> styled to match the VUEDA control shell. Used where a JS-driven SelectTrigger or ComboboxTrigger would be overkill: short fixed enums on touch devices, environments where native menu UX is preferred. Same control-height + hairline + focus + aria-invalid shell as Input.root, but because it is a picker (click to open) rather than a text field it also carries the trigger-hover affordance the other pickers use: hairline-border-strong on the edge in both modes plus a dark-mode --accent fill step. appearance-none strips the native chevron and pr-9 reserves space for the icon the consumer paints. The option surface inside the dropdown is owned by the OS; deep styling lives in the JS-driven pickers. |
| NativeSelectOptGroup | key | 1 | The native <optgroup> tinted to inherit the popover surface so the system's native dropdown reads as the same surface family as VUEDA's JS-driven pickers. The OS owns layout and the divider between groups; this slot only paints the background. |
| NativeSelectOption | key | 1 | The native <option> tinted to inherit the popover surface. Per-row layout, highlight, and check indicator are all owned by the OS; for richer option chrome (icons, sub-labels, highlighted-vs-checked distinction) use SelectItem or ComboboxItem. |
| NumberField | key | 1 | The outer grid wrapper for a numeric input with optional increment / decrement steppers. Pure layout (grid gap-1.5) so a label, the input, and any messaging stack at the standard form rhythm. The visible input chrome lives on NumberFieldInput.root; the absolute-positioned steppers are anchored by NumberFieldContent.root. |
| NumberFieldContent | key | 1 | The inner wrapper that hosts NumberFieldInput.root plus the optional stepper buttons. Reserves horizontal pad on the input (pl-5 / pr-5) only when NumberFieldDecrement / NumberFieldIncrement are actually rendered, so a stepperless number field keeps the standard control padding and a stepper-bearing one never crashes a digit string into the glyphs. relative is the anchor for the absolute-positioned steppers. |
| NumberFieldInput | key | 1 | The numeric <input> itself. Same hairline + focus shell as Input.root, but renders in mono + tabular numerals and centres the value so digit widths stay stable while a stepper cycles through different-length numbers. Mono is the segment-as-token treatment shared with the date / time fields. |
| NumberFieldDecrement | key | 1 | The decrement stepper anchored to the left edge of NumberFieldInput.root. Absolutely positioned so the stepper overlays the input rather than competing for row width; disabled:opacity-20 reads as "at the lower bound" — a stronger fade than the standard 50% control-disabled treatment so a temporarily unusable stepper does not look like a fully disabled field. |
| NumberFieldIncrement | key | 1 | The increment stepper anchored to the right edge of NumberFieldInput.root. Mirror of NumberFieldDecrement.root; same overlay positioning and same upper-bound fade. |
| DateField | key | 1 | The input-shaped shell hosting the editable date segments. Same hairline + focus + aria-invalid recipe as Input.root, with the row of DateFieldInput.root segments laid out as flex items inside; sizes pick the standard h-vueda-control* tier from base.css § Control sizing. The read-only treatment swaps to bg-muted/50 so a frozen date field reads as the same surface family as a read-only text input. |
| DateFieldInput | key | 1 | A single editable date segment (year / month / day). Renders in --vueda-font-mono at font-medium with font-feature-settings: 'tnum','zero' so digit widths stay stable as values change and 0 remains visually distinct from O. The focused segment paints --accent / --accent-foreground (same recipe as a menu-item-highlighted row, since a focused segment is a selection); caret-transparent hides the text caret because segments edit via arrow keys rather than free-form typing, and data-[placeholder] mutes the segment to --muted-foreground while empty. |
| DateRangeField | key | 1 | The input-shell variant that joins a start / end DateRangeFieldInput.root pair into one chip. See also: DateField.root for the shared shell recipe; delta is that the row hosts two segment runs separated by a literal separator glyph rendered by the component rather than a single run. |
| DateRangeFieldInput | key | 1 | An editable segment inside a DateRangeField.root. See also: DateFieldInput.root; same mono + tabular + slashed-zero, accent-on-focus, caret-transparent recipe applies. |
| TimeField | key | 1 | The input-shell variant for editable time segments (hour / minute, plus optional second / period). See also: DateField.root; identical shell and size-tier recipe, only the segment set inside differs. |
| TimeFieldInput | key | 1 | An editable segment inside a TimeField.root. See also: DateFieldInput.root; identical recipe. |
| Calendar | key | 1 | The outer surface that hosts the month grid. Pure 12px padding (p-3) and no border or shadow of its own; chrome belongs to the host (a PopoverContent.root when used in a date-picker popover, or the surrounding view when embedded inline). No footer either: CalendarFooter.root is a separate chin attached below by composition, so a footer-free embed renders as a bare grid. |
| CalendarHeader | key | 1 | The title row above the day grid. Flex-centred so the CalendarHeading.root sits in the middle of the row, with px-8 reserving 32px of side padding for the prev / next CalendarNavButton.root pair that the component anchors to the row edges. |
| CalendarHeading | key | 1 | The month-year title text inside a CalendarHeader.root. Single-line text-sm font-medium; sits centred between the prev / next nav buttons. |
| CalendarNavButton | key | 1 | The prev / next month button anchored to a CalendarHeader.root. Composes _ButtonBase.root plus _ButtonOutline.root for the neutral chip recipe, then overrides to a square 28×28 transparent chip with opacity-50 at rest and full opacity on hover so the chrome stays out of the way until the user reaches for it. One theme key serves both directional SFCs (CalendarPrevButton, CalendarNextButton); the RangeCalendarPrevButton.root / RangeCalendarNextButton.root pair on the range side stays split. Whether the two sides should converge on one shape is unsettled. |
| CalendarGrid | key | 1 | The 7-column day grid. border-collapse lets adjacent cell borders share one hairline rather than doubling at the seam; w-full lets the grid stretch to the Calendar.root content width so cell sizing falls out of flex-1 on CalendarCell.root. |
| CalendarGridRow | key | 1 | A single week row inside a CalendarGrid.root. Flex row; cell width comes from flex-1 on the children, not from a column template. |
| CalendarHeadCell | key | 1 | A weekday-label cell (Mo / Tu / We ...) above the day grid. Width pins to --vueda-cal-cell (32px) so labels align under the day-button slots below; renders at 0.8rem on --muted-foreground so the header row reads as chrome rather than as a row of day buttons. |
| CalendarCell | key | 1 | A grid slot inside a CalendarGridRow.root; the CalendarCellTrigger.root day button sits inside it. p-0 so the button owns the inner spacing, flex-1 distributes width evenly across the row, and relative plus focus-within:z-20 lets a focused day button promote above its neighbours when the focus ring would otherwise be clipped by adjacent cells. |
| CalendarCellTrigger | key | 1 | The pressable day button inside a CalendarCell.root. Composes _ButtonBase.root plus _ButtonGhost.root so day buttons share the popover-friendly hover recipe with the rest of the picker chrome. Size pins to --vueda-cal-day (30×30) so the button sits inside the 32px CalendarCell.root with a 1px breathing margin. Carries the picker's full state matrix: data-selected paints --primary / --primary-foreground, data-today (when not selected) paints --accent, data-disabled and data-outside-view mute to --muted-foreground, and data-unavailable paints --destructive plus line-through. |
| CalendarFooter | key | 2 | The optional chin slot below a Calendar.root or RangeCalendar.root. Flex row with a border-t separator and an 8px gap; used by date-picker popovers that need a date-summary line plus an action row (Apply / Clear). Calendar and RangeCalendar themselves stay footer-free so the bare grid can be embedded without chrome it cannot use. |
| RangeCalendar | key | 1 | See also: Calendar.root; identical 12px-padded surface, only the grid inside differs (the RangeCalendarCell.root carries the range-fill state). |
| RangeCalendarHeader | key | 1 | The title row above a RangeCalendar.root's day grid. See also: CalendarHeader.root; delta is that the prev / next buttons inside (RangeCalendarPrevButton.root / RangeCalendarNextButton.root) anchor to the row edges via position: absolute, so this header does not reserve px-8 the way the single-calendar header does. |
| RangeCalendarHeading | key | 1 | See also: CalendarHeading.root; identical recipe. |
| RangeCalendarPrevButton | key | 1 | The previous-month button anchored to the left edge of a RangeCalendarHeader.root. Composes _ButtonBase.root plus _ButtonOutline.root, then absolute-positions itself at left-1 so the button does not consume row flex while the heading floats centred between the two edges. Same square 28×28 transparent plus 50%-opacity-at-rest treatment as CalendarNavButton.root. |
| RangeCalendarNextButton | key | 1 | See also: RangeCalendarPrevButton.root; mirror anchored to the right edge of the header at right-1. |
| RangeCalendarGrid | key | 1 | See also: CalendarGrid.root; identical recipe. |
| RangeCalendarGridRow | key | 1 | See also: CalendarGridRow.root; identical recipe. |
| RangeCalendarHeadCell | key | 1 | See also: CalendarHeadCell.root; identical recipe (the class-order difference vs the single-calendar slot is incidental, not a deliberate departure). |
| RangeCalendarCell | key | 1 | A grid slot inside a RangeCalendarGridRow.root. Same p-0 plus relative plus focus-within:z-20 layout shape as CalendarCell.root, plus the range-fill recipe: [&:has([data-selected])]:bg-accent paints --accent on the cell (not on the day button) whenever the inner trigger is part of the selected range, so middle cells render as a continuous strip while the data-selection-start and data-selection-end cells round only their outer corners via the [&:has([data-selected][data-selection-start])] / [&:has([data-selected][data-selection-end])] variants. Range fill goes on the cell rather than the day button so the run can round cleanly at its endpoints. |
| RangeCalendarCellTrigger | key | 1 | The pressable day button inside a RangeCalendarCell.root. See also: CalendarCellTrigger.root; delta is that the single data-selected state is replaced by paired data-selection-start / data-selection-end states that paint --primary only at the two endpoints, leaving the middle of the range to read through the --accent fill that RangeCalendarCell.root paints on its cell. |
| ComboboxAnchor | key | 1 | The positioning anchor for the ComboboxList.root popover. Pins to a 200px width by default so a Combobox that anchors to whitespace (rather than the trigger element) still has a sensible reference rectangle; consumers that wrap the trigger in the anchor inherit the trigger's width instead and can ignore this default. Layout-only slot; no chrome of its own. |
| ComboboxTrigger | key | 1 | The pressable surface that opens the ComboboxList.root. Ships empty today: in-tree consumers (WidgetCombobox) supply their own input-shell chrome via asChild, so the bare primitive has no usable default. The Combobox-vs-Select differentiator (Combobox reads as a field because the user is about to type) is enforced by consumers, not by this slot. Giving the bare primitive an input-shell default is deferred until the same session settles the multi-select div-trigger pattern, since one API choice covers both. |
| ComboboxList | key | 1 | The floating popover surface that holds the ComboboxItem.root rows. Reads as a popover: 2px control radius, --popover fill, and a hairline edge with popover elevation (overlay-hairline), with the standard side-aware enter / exit transforms anchored on --reka-combobox-content-transform-origin so the surface scales out of the corner closest to the trigger. Fixed 200px width matches ComboboxAnchor.root; the inner ComboboxViewport.root owns scrolling. |
| ComboboxViewport | key | 1 | The scrollable region inside ComboboxList.root that wraps the result groups. Caps at 300px tall before the viewport begins to scroll; scroll-py-1 keeps a hairline of breathing room above the first and below the last visible row so a focused item never crashes into the viewport edge. |
| ComboboxInput | key | 1 | The search field at the top of a ComboboxList.root. Sized to the large control-height tier (h-vueda-control-lg) so the input reads as the primary surface inside the popover; renders chrome-free (bg-transparent, no border or focus ring) because the surrounding popover already owns the elevation and ring contracts. The Combobox trigger that opens the popover wears the input shell instead. |
| ComboboxGroup | key | 2 | A section of related ComboboxItem.root rows inside ComboboxList.root. 4px padding (p-1) carries the breathing room around the section so consecutive groups read as separate runs even without a ComboboxSeparator.root between them; overflow-hidden clips a long inner row to the group's box rather than letting it bleed into a neighbour. |
| ComboboxItem | key | 1 | A single result row inside a ComboboxGroup.root. The data-highlighted state (set by the picker on keyboard or pointer focus) paints --accent / --accent-foreground, and the muted leading icon flips to inherit on the same rule so a highlighted row reads as one tinted strip. data-disabled halves opacity and drops pointer events; rounded-sm keeps the row a chit inside the group's slab. The committed-value data-state=checked tint that SelectItem.root carries is not applied here because Combobox commits by closing the popover; the trailing ComboboxItemIndicator.root marks the selection instead. |
| ComboboxItemIndicator | key | 1 | The trailing selected-state glyph on a ComboboxItem.root (typically a check mark). ml-auto pushes the indicator to the row's trailing edge; size and colour are inherited from the surrounding row so the indicator picks up the highlight swap without painting its own state. |
| ComboboxSeparator | key | 1 | A 1px horizontal divider between groups inside ComboboxList.root. Renders as a flat --border hairline rather than the DPR-aware hairline utility because the separator sits inside a popover that already paints its own border at the same width, so the visual seam never reads as a doubled line. -mx-1 extends the divider to the popover edge past the group's 4px inner padding. |
| ComboboxEmpty | key | 1 | The zero-result placeholder shown inside ComboboxList.root when the search has no matches. Centred sm text inside 24px vertical padding so the empty state reads as a deliberate pause rather than a collapsed popover; consumers supply their own copy. |
| Command | key | 1 | The outer Command surface (a search + categorised result list). 4px card radius rather than the 2px control radius the rest of the picker family wears, because Command is a shell surface, not a slab control. The flex-column layout stacks CommandInput.root, CommandList.root, and optional CommandFooter.root into one chip, and overflow-hidden lets the inner list scroll without escaping the rounded corners. Used inline or hosted inside a CommandDialog.content. |
| CommandInput | key | 2 | The free-text search field at the top of a Command.root. Renders chrome-free at --vueda-cmd-input-height so the surrounding CommandInput.wrapper owns the row's geometry and the lower hairline; the input itself just contributes placeholder, focus-clear, and the disabled treatment. |
| CommandList | key | 1 | The scrollable region of Command.root that holds the result groups. See also: ComboboxViewport.root; identical 300px cap and scroll-py-1 recipe so both pickers feel the same when keyboard navigation crosses the viewport edge. |
| CommandEmpty | key | 1 | The zero-result placeholder shown inside CommandList.root when the search has no matches. See also: ComboboxEmpty.root; identical recipe. |
| CommandGroup | key | 2 | A section of related CommandItem.root rows inside CommandList.root. See also: ComboboxGroup.root; identical recipe. |
| CommandItem | key | 1 | A single result row inside a CommandGroup.root. See also: ComboboxItem.root; identical highlight + disabled + icon-tint recipe so result rows feel the same across both pickers. Command differs only at the row's trailing edge, where CommandShortcut.root (rather than ComboboxItemIndicator.root) marks the kbd hint for invoking the action. |
| CommandSeparator | key | 1 | A 1px horizontal divider between groups inside CommandList.root. See also: ComboboxSeparator.root; identical recipe. |
| CommandShortcut | key | 3 | Alignment wrapper for the trailing keyboard hint on a CommandItem.root. ml-auto pushes the hint flush right while the nested KbdGroup.root owns the chord. |
| CommandFooter | key | 3 | The optional chin below CommandList.root. Sits at --vueda-cmd-footer-height (32px) on --muted with a top hairline, holding keyboard-navigation hints on the leading edge and custom action labels on the trailing edge; supporting-size copy on --muted-foreground reads as status rather than primary chrome. |
| CommandDialog | key | 2 | The DialogContent.root pane that hosts a Command.root at modal scale. Drops all padding so Command's own card radius, fill, and inner geometry own the dialog box, and overflow-hidden keeps the inner list's scroll edges clipped to the rounded corners. |
| SelectTrigger | key | 1 | The pressable surface that opens a SelectContent.root. Reads as a neutral chip (transparent at rest, hairline border, shadow-vueda-control micro-shadow, control-radius corners) rather than the input shell ComboboxTrigger.root wears, because Select is an enum picker and the user is not about to type. Hover paints hairline-border-strong (one step darker than the resting hairline) without firing the focus ring. Three size tiers ride h-vueda-control* plus matching px-vueda-control-px*; dark mode rests on the input tint (bg-input/30) and hovers the fill to --accent (a perceptible lightness step, since the old bg-input/50 topped out near the rest lightness because --input is itself dark), and aria-invalid swaps both the hairline and the focus-ring shadow to destructive. Placeholder text mutes to --muted-foreground so an unselected trigger reads as empty rather than as a chosen value. |
| SelectContent | key | 2 | The floating popover surface that holds the SelectItem.root options. Reads as a popover (2px radius, a hairline edge with popover elevation via overlay-hairline) capped at the viewport-available height that Reka exposes via --reka-select-content-available-height; the popper-position-only translate nudges (translate-y-1, etc.) sit the popover one 4px step off the trigger so the surface does not crash into the chip that opened it. The item-aligned legacy mode (the popover aligns itself to the selected item rather than anchoring to the trigger) skips those nudges and shares all other chrome. |
| SelectItem | key | 1 | A single option inside a SelectContent.viewport. Carries the two-track selection state that distinguishes Select from Combobox: the highlighted-but-not-committed option paints --accent / --accent-foreground on :focus, while the committed value (data-state=checked) tints with bg-primary/10 so the chosen option reads as a soft primary band even when another row is highlighted; the indicator icon alone is not a strong enough signal at rest. pr-8 reserves trailing space for the check indicator; rounded-sm keeps the option a chit inside the popover slab. |
| SelectLabel | key | 1 | The section heading inside a SelectContent.root. See also: ComboboxGroup.heading; same caps-micro eyebrow on --muted-foreground (the rendered class list drops the leading font-mono, but Tailwind's default sans / mono cascade leaves the eyebrow visually identical at the micro size). |
| SelectSeparator | key | 1 | A 1px horizontal divider between sections inside SelectContent.viewport. See also: ComboboxSeparator.root; delta is a vertical 4px margin (my-1) so the divider breathes against the surrounding 4px viewport padding, plus pointer-events-none so the hairline never intercepts a click meant for a neighbouring row. |
| SelectScrollUpButton | key | 1 | The scroll-up affordance that surfaces at the top of a long SelectContent.viewport. 4px tall flex centre so the slot reads as a thin handle rather than a button; the consumer paints the chevron glyph inside. Reka shows / hides the slot automatically based on scroll position. |
| SelectScrollDownButton | key | 1 | See also: SelectScrollUpButton.root; mirror at the bottom of the viewport. |
| TagsInput | key | 1 | The outer shell of a multi-value input that captures discrete entries as pill chips. Reads as the input family: hairline border, control radius, shadow-vueda-control micro-shadow, dark-mode bg-input/30 tint. Flex-wrap with an 8px gap so committed TagsInputItem.root chips and the trailing TagsInputInput.root flow onto new rows as the chip count grows. Focus and aria-invalid rings fire on the shell (not the inner input) via :has(input:focus-visible) and :has([data-state=active]) selectors: typing in the field paints the standard focus ring on the shell; focusing a committed chip (data-state=active) suppresses the shell ring so the chip's own active outline is the only one visible at a time. |
| TagsInputInput | key | 1 | The free-text entry field inside a TagsInput.root. Sized to --vueda-chip-height so pending text shares a baseline with the committed chips beside it; renders chrome-free (transparent fill, no border, no focus ring) because the surrounding shell owns the chip-row contract and fires the focus ring on its own when the input is focused. flex-1 lets the field absorb the remaining row width inside the wrap so the typing affordance always reaches the trailing edge. |
| TagsInputItem | key | 1 | An individual committed chip inside a TagsInput.root. Pill radius (not the control / card radius the rest of the form family wears) marks the chip as a user-manipulated tag object rather than a slab-radius system badge or a chrome chit. Sized to --vueda-chip-height so multiple chips on a row share one baseline. data-state=active (set when the chip receives keyboard focus to edit or delete it) paints the standard focus ring on the chip, and the surrounding TagsInput.root suppresses its own ring on the same condition so only one ring paints at a time. |
| TagsInputItemText | key | 1 | The text label inside a TagsInputItem.root. 4px / 8px padding on a transparent fill so the label reads as content sitting inside the secondary-tinted chip rather than carrying its own surface; sm size matches the surrounding TagsInputInput.root so committed and pending text share a tier. |
| TagsInputItemDelete | key | 1 | The remove (x) button at the trailing edge of a TagsInputItem.root. Transparent fill so the button rides on the chip's secondary surface rather than punching its own swatch; the trailing 4px margin separates the glyph from the chip's pill end so the hit target does not run into the rounded edge. |
| Checkbox | key | 2 | The boolean-chit shell. 24px square at a 4px corner (one step softer than the 2px control radius) so it reads as a chit rather than a miniature slab control. Default state paints a hairline edge on the input-tinted surface and carries the standard focus + aria-invalid ring contract. In dark mode the rest edge swaps to --border-strong (dark:hairline-border-strong) so an unchecked box stays visible on hovered list rows, where the opaque --input edge would sink into the bg-accent/50 hover band. Checked and indeterminate states fill with --primary and drop the hairline (the --vueda-hairline-color:transparent override on the same selectors) so the surface reads as a single solid swatch; aria-invalid swaps both the fill and the painted edge to --destructive. The inline-flex centring and align-middle hold the box to a fixed size-6 square with a stable baseline whether or not it is checked; keep them when overriding this slot, or toggling a checkbox can reflow baseline-aligned parents (for example the card-layout ObjectsGrid grid). |
| RadioGroup | key | 1 | Layout shell for a vertical run of RadioGroupItem.root. 12px gap (gap-3) so the items breathe at the form-level density; the items, not the group, carry the focus and aria-invalid rings, so the group itself is a transparent layout container. Override to flex or grid-flow-col for a horizontal stack without touching the per-item contract. |
| RadioGroupItem | key | 3 | The individual radio chit inside a RadioGroup.root. 24px circle, paired with the 24px Checkbox.root square so the two single-select families share a row height. hairline edge on an input-tinted surface (dark:bg-input/30) with the standard focus + aria-invalid ring contract; the dark rest edge uses --border-strong (parity with Checkbox.root) so the ring stays visible on hovered list rows. Selected state is carried by the inner RadioGroupItem.dot via text-primary on the root (the dot inherits the colour through bg-current); aria-invalid recolours the dot to --destructive the same way. |
| Switch | key | 2 | The track of the sliding boolean control. Tighter than the iOS-canonical size: 18.4px tall (h-[1.15rem]), 32px wide (w-8), so the switch sits at the form density tier rather than ballooning above the 32px control row. Pill radius; checked fills --primary, unchecked fills --input (with a darker --input/80 tint in dark mode for visibility against the deeper canvas). Focus paints --ring directly on the otherwise-transparent 1px border and adds a 2px outline at 2px offset, rather than the canon focus-ring utility, because the track + thumb composition needs the ring to wrap the entire pill without the inset shadow variant interfering with the thumb's transform. |
| Slider | key | 4 | The continuous-value control surface. Flex row by default; data-[orientation=vertical] flips to flex column and applies a 176px (min-h-44) minimum height so a vertical slider has enough travel to be precise. touch-none and select-none so dragging the Slider.thumb does not scroll the page or initiate a text selection. data-[disabled]:opacity-50 is the disabled signal; pointer events are blocked at the Reka primitive level above this slot, so no cursor-not-allowed is needed on the root. |
grid
| Component | Kind | Slots | Description |
|---|---|---|---|
| Table | key | 2 | The scroll container around the native table. It owns the card surface, horizontal overflow, and sticky-table height cap used when Table receives sticky. |
| TableBody | key | 1 | The <tbody> section wrapper. It removes the last row's divider from that row's cells so the enclosing Table.container edge remains the closing edge instead of doubling the table bottom. |
| TableCaption | key | 1 | The native caption below a table. Use it for low-emphasis supporting copy tied to the table, with spacing that keeps it visually outside the bordered data surface. |
| TableCell | key | 1 | The body cell slot for <td> elements. It applies the density tiers from Table.table, keeps checkbox columns compact, and honors data-numeric or data-mono directly on the cell. |
| TableEmpty | key | 2 | The spanning empty-state cell. It keeps the row aligned with regular TableCell.root cells while allowing colspan and consumer classes to define the empty row's table footprint. |
| TableFooter | key | 1 | The <tfoot> section wrapper for summary and total rows. Its muted fill and top divider separate aggregates from body rows while leaving row cells free to handle numeric alignment. The divider sits on the first footer row's cells, and the last footer row drops its own divider, because the separated border model does not paint borders on <tfoot> or <tr>. |
| TableHead | key | 1 | The header cell slot for <th> elements. It owns compact header typography, density heights, sticky positioning, checkbox offsets, and numeric sort-icon ordering; see Table.table. |
| TableHeader | key | 1 | The <thead> section wrapper. Empty by default: header cells take their bottom divider from TableRow.root, and because that border belongs to the cell, a sticky TableHead.root carries it over scrolling body content. |
| TableRow | key | 1 | The row slot shared by header, body, and footer sections. It provides hover feedback, selected-row tinting, the leading selected rail, and the standard divider. The divider sits on the row's cells rather than the <tr>: Table.table uses the separated border model, which does not paint borders on rows. |
| TableRowActions | key | 2 | The inline wrapper for row actions. It stays invisible until the row is hovered, focused within, or selected, keeping scan-heavy tables clear until actions are relevant. |
objects-grid
| Component | Kind | Slots | Description |
|---|---|---|---|
| ObjectsGrid | key | 11 | The outer scroll surface and card chrome for the grid. It owns the density attribute, tabular number rendering, and data-flush edge merging used when the grid is embedded in a parent surface. data-flush strips the embedded grid's border and radius so only the parent container's edge remains visible. |
| ObjectsGridTableHeader | key | 2 | The header content wrapper. It lays out the label and the numeric-column reversal used when the parent header cell carries data-numeric. |
| ObjectsGridCardCell | key | 2 | The card-layout field label fragment. It renders as a compact muted micro-label that participates directly in ObjectsGrid.cardContainer. |
| ObjectsGridBodyCell | key | 2 | The table-layout field cell. It provides density-aware row height, numeric and mono alignment hooks, and the foreground text treatment for value slots. Density tiers map default, compact, and condensed rows to progressively tighter row heights. |
form
| Component | Kind | Slots | Description |
|---|---|---|---|
| FieldSetMany | key | 9 | Card shell for a repeated-value fieldset. See also: FieldSetStackedInline.root. |
| FieldSetRange | key | 8 | Card shell for paired lower and upper range fields, including nested-fieldset inset chrome. |
| FieldSetStackedInline | key | 20 | Card shell for stacked inline rows, including nested-fieldset inset chrome. |
| FieldSetStackedInlineRow | key | 7 | Bordered row card with dirty and selected-for-destroy state chrome. |
| FieldSetTabularInline | key | 25 | Card shell for tabular inline editing, including nested-fieldset inset chrome. |
| FilterChip | key | 5 | Pill container. Primary tint at rest; destructive tint flags a value the server rejected. |
| FilterFieldForm | key | 2 | Submit row at the foot of the form. Apply alone (right-aligned) when adding; Remove + Apply split apart when editing an active filter. |
| FilterForm | key | 2 | Vertical form body inside a filter popover. |
| FilterGroup | key | 6 | Root wrapper. contents so it adds no box of its own: the teleported menu trigger and the chips strip flow as direct children of the list layout. |
| FilterMenu | key | 3 | Back row that returns from the drill-in form to the field list. |
| FormMessage | key | 2 | Outer spacing for form-scope feedback. |
| FormModel | key | 8 | Root model-form wrapper. |
| FormSection | key | 3 | Section stack for a long-form group. |
| FormSectionTitle | key | 1 | Eyebrow heading text for a form section. |
| FormGrid | key | 1 | Twelve-column field grid with data-col span hooks at the form breakpoint. |
| FormActions | key | 2 | Wrapping action row for submit, cancel, and secondary controls. |
| FormHiddenFeedback | key | 9 | Compact wrapper for hidden-field feedback controls. |
| FieldWarningsList | key | 5 | Wrapper stacking each field's warning entry. |
| TypedConfirmField | key | 4 | Muted confirmation box that groups the label and input before a destructive action. |
widgets
| Component | Kind | Slots | Description |
|---|---|---|---|
| WidgetCheckbox | key | 4 | The outer row aligns the checkbox control with its label chrome. |
| WidgetCombobox | key | 1 | The trigger uses the input-shell recipe for searchable pickers. |
| WidgetDuration | key | 3 | The root intentionally carries no chrome so form layout owns spacing. |
| WidgetFile | key | 5 | The root stays transparent so the field shell provides the surface. |
| WidgetGenericAutoComplete | key | 4 | The root remains unstyled so the widget can sit inside any form shell. |
| WidgetHtml | key | 6 | The root adds no spacing so form composition controls the editor block. |
| WidgetImage | key | 3 | The root is transparent so image widgets inherit the surrounding field rhythm. |
| WidgetJson | key | 2 | Bordered control surface that mirrors textarea invalid and disabled states. |
| WidgetReadOnly | key | 10 | The root has no chrome because read-mode rows are owned by the field shell. |
| WidgetLabel | key | 5 | The root grid pairs label text with feedback actions above the control. |
| WidgetPreviewableTemplate | key | 7 | The root adds no chrome so the surrounding form section owns spacing. |
| WidgetTemplateLegend | key | 3 | The root stays unstyled so the legend can be embedded beside any template widget. |
shell
| Component | Kind | Slots | Description |
|---|---|---|---|
| Accordion | key | 1 | The root hook for the accordion wrapper. It intentionally ships without chrome so callers can compose accordion groups inside Card, Item, or plain page sections. |
| AccordionItem | key | 1 | The wrapper for one disclosure row. It paints the simple bottom divider and removes it from the final item, keeping accordion chrome owned by items rather than the root. |
| AccordionContent | key | 2 | The animated collapsible content region. It owns the open and closed height animations and applies body text sizing while leaving padding to AccordionContent.inner. |
| AccordionTrigger | key | 3 | The clickable accordion header. It uses the container typography rhythm, exposes a focus outline, and rotates direct SVG icons when the item is open. |
| AlertDialogAction | key | 1 | Extra classes for the Button rendered inside AlertDialogAction. Button owns the tone, emphasis, size, focus, and disabled recipes; this slot is intentionally empty by default so the wrapper cannot drift from the button contract. |
| AlertDialogCancel | key | 1 | Extra classes for the Button rendered inside AlertDialogCancel. Button owns the tone, emphasis, size, focus, and disabled recipes; this slot only adds mobile spacing for the stacked alert-dialog footer layout. |
| AlertDialogContent | key | 2 | The centered alert dialog surface. It uses the modal radius, overlay shadow, fixed viewport centering, and entrance or exit motion expected for blocking confirmations. |
| AlertDialogDescription | key | 1 | The supporting copy below an alert dialog title. It uses muted small text so consequence detail supports the title without competing with the action buttons. |
| AlertDialogFooter | key | 1 | The action row for an alert dialog. It stacks buttons in reverse order on narrow screens and aligns them to the end once horizontal space is available. |
| AlertDialogHeader | key | 1 | The title and description stack at the top of an alert dialog. It centers copy on narrow screens and switches to left alignment at the small breakpoint. |
| AlertDialogTitle | key | 1 | The primary heading for an alert dialog. It uses a compact semibold heading treatment sized for modal content, not page-level display text. |
| Collapsible | key | 1 | The root hook for generic collapsible state. It intentionally has no visual recipe because Collapsible is a logic primitive. |
| CollapsibleContent | key | 1 | The region controlled by a CollapsibleTrigger. It ships empty so feature surfaces can decide whether the content behaves like inline reveal, row detail, or raw-debug disclosure. |
| CollapsibleTrigger | key | 1 | The trigger hook for a generic collapsible. It ships empty so callers can use links, rows, buttons, or custom controls without inheriting accordion chrome. |
| Card | key | 1 | The framed card surface. It owns the card background, border, radius, vertical rhythm, and non-raised shadow contract; padding on the horizontal axis belongs to child slots. |
| CardHeader | key | 1 | The leading card header grid. It creates title and description rows and switches to a two-column layout when CardAction.root is present. |
| CardTitle | key | 1 | The primary title text inside a card header. It uses compact semibold type so card headings stay subordinate to page titles. |
| CardDescription | key | 1 | The secondary card header copy. It uses muted body text for explanatory text below CardTitle.root. |
| CardAction | key | 1 | The trailing card header action region. It parks in the top-right column and spans the title and description rows without adding wrapper layout logic. |
| CardContent | key | 1 | The body content inset for a card. It provides the horizontal padding that Card itself omits so full-width header or footer borders can span cleanly. |
| CardFooter | key | 1 | The trailing card footer row. It aligns footer content horizontally and adds top padding when the footer carries a top divider (a raw border-t or the DPR-tracked border-t-hairline; prefer the hairline form, see README § 7.3). |
| DialogContent | key | 2 | The dialog surface. Standard dialogs use fixed viewport centering, the modal radius, and overlay shadow; full-screen dialogs replace that geometry with a viewport-filling surface. Both own the paired background and foreground tokens. |
| DialogDescription | key | 1 | The supporting copy below a dialog title. It uses muted small text so detail remains subordinate to the title and body content. |
| DialogFooter | key | 1 | The action row for dialog footers. It stacks in reverse order on narrow screens and aligns trailing actions on wider screens. |
| DialogHeader | key | 1 | The title and description stack at the top of a dialog. It centers copy on narrow screens and switches to left alignment at the small breakpoint. |
| DialogOverlay | key | 1 | The dialog backdrop layer. It fills the viewport with the shared overlay token and fades with dialog state changes. |
| DialogScrollContent | key | 3 | The scrollable dialog surface. It stays centered inside the scroll overlay while preserving the modal radius, border, and overlay shadow used by dialog surfaces. |
| DialogTitle | key | 1 | The primary heading for a dialog. It uses compact semibold type sized for modal content, not page-level display text. |
| Field | key | 1 | The outer field layout wrapper. It switches between vertical, horizontal, responsive, and read-only grid layouts while carrying invalid state color. |
| FieldContent | key | 1 | The non-label content stack inside a field. It groups controls, helper text, and validation messages into a compact flex column. |
| FieldDescription | key | 1 | The helper text beneath or beside a field control. It uses supporting text size, muted color, and link styling that keeps explanatory copy readable without becoming the primary label. |
| FieldGroup | key | 1 | The stack for related fields and nested field groups. It establishes the field-group container query used by responsive fields and tightens spacing for checkbox and radio groups. |
| FieldLabel | key | 1 | The label text or label-card wrapper for a field. It handles disabled opacity, nested control-card framing, and checked-state tint for label-wrapped choices. |
| FieldLegend | key | 1 | The legend or label-style heading for grouped fields. Its variant attribute chooses between larger legend text and compact label text. |
| FieldMessage | key | 2 | The validation or warning message attached to a field. It maps error severity to destructive text and all other severities to warning text. |
| FieldSeparator | key | 3 | The positioned wrapper for a labelled field divider. It reserves the line height and variant-specific vertical offset used inside field groups. |
| FieldSet | key | 1 | The stack for a fieldset's child fields. It uses the default field rhythm and tightens spacing when the direct child is a checkbox or radio group. |
| FieldTitle | key | 1 | The compact title text adjacent to field content. It follows field disabled opacity and uses label-weight type for local field headings. |
| HoverCardTrigger | key | 1 | The trigger hook for hover-card content. It ships empty so the trigger can inherit the semantics and visual treatment of the element that owns the hover affordance. |
| HoverCardContent | key | 1 | The floating hover-card panel. It uses the popover surface recipe at a tighter width for glance-weight summaries. |
| Item | key | 1 | The row-like item wrapper. It carries the default, outline, and muted variants, size spacing, anchor hover behavior, and focus treatment. |
| ItemActions | key | 1 | The trailing action group inside an item. It keeps adjacent controls aligned and evenly spaced without affecting the main content column. |
| ItemContent | key | 1 | The main text stack inside an item. It flexes to fill available space and lets a following content block opt out of that growth. |
| ItemDescription | key | 1 | The secondary item copy. It clamps to two lines, uses muted body text, and styles links as quiet inline affordances. |
| ItemFooter | key | 1 | The low-emphasis metadata row below item content. It uses compact mono supporting text so timestamps, counters, and machine-generated values read as metadata. |
| ItemGroup | key | 1 | The stack wrapper for related items. It opens a named group scope and leaves borders or section chrome to the caller. |
| ItemHeader | key | 1 | The low-emphasis metadata row above item content. It mirrors ItemFooter.root for compact mono metadata before the title. |
| ItemMedia | key | 1 | The leading media region for an item. The icon variant creates a 32px bordered tile, the image variant creates a 40px cropped image frame, and the default stays transparent. |
| ItemSeparator | key | 1 | The divider between item rows. It removes extra vertical margin so separators can be used in dense item groups. |
| ItemTitle | key | 1 | The primary label inside an item. It uses body-sized medium text and inline gap support for leading or trailing inline elements. |
| Label | key | 1 | The accessible label text for controls and grouped inputs. It handles disabled states from both group and peer contexts while preserving compact inline alignment. |
| PopoverContent | key | 1 | The positioned popover panel. Uses the shared floating surface recipe. Width is not set here — the element uses width: auto (shrink-to-fit) by default; pass a class prop to the PopoverContent component to set a specific width or minimum if the content needs one. |
| ResizableHandle | key | 2 | The draggable divider between resizable panels. It expands the hit area around the 1px visual rule and adapts the affordance for horizontal or vertical panel groups. |
| ResizablePanelGroup | key | 1 | The flex container for resizable panels. It switches from row to column layout when the panel group orientation is vertical. |
| ScrollArea | key | 2 | The root wrapper for a custom scroll area. It establishes relative positioning for scrollbars without adding surface chrome. |
| ScrollBar | key | 2 | The custom scrollbar track. It uses a 10px touch target and switches its border side and dimensions by orientation. |
| Separator | key | 1 | The plain horizontal or vertical dividing rule. It is a single border-token line with no label or inset variant. |
| DrawerContent | key | 2 | The edge-attached drawer surface. It reads Vaul direction attributes to choose edge, size, max height, and which modal-radius corners stay rounded. |
| DrawerDescription | key | 1 | The supporting copy inside a drawer. It uses muted small text to stay subordinate to the drawer title and body content. |
| DrawerFooter | key | 1 | The trailing action area inside a drawer. It pins itself after drawer body content and stacks actions with the standard 4px-grid gap. |
| DrawerHeader | key | 1 | The title and description stack inside a drawer. It applies the drawer's default 16px inset and compact vertical gap. |
| DrawerOverlay | key | 1 | The drawer backdrop layer. It fills the viewport with the shared overlay token and fades with drawer state changes. |
| DrawerTitle | key | 1 | The primary heading inside a drawer. It uses foreground semibold text without page-title scaling. |
| SheetContent | key | 2 | The edge-attached sheet surface. It maps the side prop to slide direction, edge border, size, and overlay shadow while preserving a flex column body. |
| SheetDescription | key | 1 | The supporting copy inside a sheet. It uses muted small text to stay subordinate to the sheet title and body content. |
| SheetFooter | key | 1 | The trailing action area inside a sheet. It sits after the body content and stacks actions with the standard inset. |
| SheetHeader | key | 1 | The title and description stack inside a sheet. It applies the sheet's default 16px inset and compact vertical gap. |
| SheetOverlay | key | 1 | The sheet backdrop layer. It fills the viewport with the shared overlay token and fades with sheet state changes. |
| SheetTitle | key | 1 | The primary heading inside a sheet. It uses foreground semibold text without page-title scaling. |
| Stepper | key | 1 | The root flex row for a stepper. It provides only the step gap so orientation and step semantics stay with the composed step items. |
| StepperItem | key | 1 | The wrapper for one step and its connector context. It opens the state group used by indicator and separator slots and suppresses pointer events when disabled. |
| StepperTrigger | key | 1 | The selectable control for a step. It stacks indicator and label content in a compact centered column with a modest focusable radius. |
| StepperIndicator | key | 1 | The circular step marker. It maps active, completed, disabled, and upcoming states to the stepper color contract. |
| StepperTitle | key | 1 | The primary label for a step. It stays on one line so horizontal steppers do not shift as labels wrap. |
| StepperDescription | key | 1 | The supporting text beneath a step title. It uses muted extra-small text for optional detail below the primary label. |
| StepperSeparator | key | 1 | The connector line between steps. It stays muted for upcoming or disabled steps and switches to accent after completion. |
| Tabs | key | 1 | The root stack for tabbed content. It keeps the tab list and active panel separated by a compact vertical gap. |
| TabsContent | key | 1 | The active tab panel. It flexes to fill remaining space and removes default outline chrome so focus treatment can be handled by child content when needed. |
| TabsList | key | 1 | The segmented tab-list surface. It uses muted fill, compact height, and a small internal padding so active triggers read as selected slabs. |
| TabsTrigger | key | 1 | The selectable tab segment. It handles active fill, dark-mode contrast, icon sizing, disabled state, and keyboard focus while staying within the segmented list surface. |
| TooltipContent | key | 2 | The compact floating tooltip panel. It inverts foreground and background tokens, uses control radius, and follows the tooltip surface rule. |
| StickyBar | key | 5 | The sticky action-bar wrapper. It stays anchored just above the page edge and translates out of view when hidden is true. |
| StickyStackProvider | key | 2 | Structural wrapper around the bars and the scrolling content. Lays them out in a column and |
| PageTitle | key | 7 | Outer header bar. Carries the bottom hairline that closes the header and, when sticky is set, pins the bar to the top of the scroll viewport at z-30. Merge extra classes via themeOverride (or setTheme) on this slot without overriding the chrome. |
views
| Component | Kind | Slots | Description |
|---|---|---|---|
| _ActionBanner | primitive | 5 | Shared banner row scaffold: icon tile plus body column with a bottom separator. |
| ActionForm | key | 19 | Outer wrapper. Caps content at the 7xl content column so a confirmation form does not stretch the full width of a wide viewport. |
| ModelActionForm | key | 26 | Outer wrapper. Empty so the card or bare slot owns all visible chrome; layout decisions belong to whichever inner shell the form renders. |
| ViewDestroy | key | 8 | Outer wrapper. Empty; the card below owns all visible chrome. |
| AuthForm | key | 7 | Outer wrapper that fills the viewport vertically so the framed card can sit against the page background without a separate page chrome. |
| AuthorizingForm | key | 7 | Outer wrapper that fills the viewport and centers the framed card both axes. Uses min-h-svh rather than min-h-full so the fill works regardless of whether an integrator's shell gives this component's ancestors an explicit height; it never depends on a height cascade it does not control. Differs from AuthForm.root which flows top-aligned; the consent step is short enough that a vertically centered card reads as a focused decision surface. |
| ViewList | key | 15 | Class forwarded to the selected_ checkbox column on the embedded ObjectsGrid. Collapses the column to w-0 at the lg+ table breakpoint so card layouts keep room for the selection toggle while the table layout absorbs it into the row chrome. The breakpoint is hard-coded rather than derived from the tableBreakpoint prop because Tailwind purges classes it cannot see at build time; keep this aligned with the prop default. |
| ViewHistoryList | key | 23 | Outer wrapper. Empty by default; the meta strip, embedded grid, and empty-state card own all visible chrome so the wrapper stays a layout-only anchor. |
| DetailView | key | 2 | Outer wrapper. Layout-only; PageTitle, the StickyBar, and the body below own the visible chrome, so this stays empty by default. The class prop merges here. |
| ViewCreate | key | 2 | Outer wrapper. Layout-only; PageTitle, the StickyBar, and the form body below own the visible chrome, so this stays empty by default. The class prop merges here. |
| ViewRead | key | 2 | Outer wrapper. Layout-only; PageTitle, the StickyBar, and the body below own the visible chrome, so this stays empty by default. |
| ViewUpdate | key | 2 | Outer wrapper. Layout-only; PageTitle, the StickyBar, and the form body below own the visible chrome, so this stays empty by default. The class prop merges here. |
| ViewLoading | key | 10 | Centering wrapper that fills the viewport vertically and centers the embedded SystemMessageCard on both axes. The card chassis is fixed-width, so a flex parent is required for it to sit in the middle of an otherwise-empty page. |
| ViewNotFound | key | 2 | Centering wrapper around the embedded SystemMessageCard. The card chassis is fixed-width, so a flex parent is required for it to sit in the middle of the viewport. Mirrors ViewLoading.root. |
| ViewActionNotFound | key | 2 | Centering wrapper around the embedded SystemMessageCard. See ViewNotFound.root; the two views share the recipe so missing-route and missing-action surfaces read as siblings. |
| ViewAction | key | 1 | Outer wrapper around the embedded PageTitle and ModelActionForm. Empty by default; the two inner shells own all visible chrome, so this key exists only as the consumer-facing override surface and the data-qa anchor. |
| ViewActivate | key | 1 | Outer wrapper around the embedded PageTitle and the activate-flow ModelActionForm. Empty by default; the chrome lives on the inner shells. The view also renders a centred LoadingSpinnerBlock while ModelActionForm's model config loads; that fallback inherits its own block recipe and is not themed here. |
| ViewDeactivate | key | 3 | Centering wrapper around the embedded warning-toned SystemMessageCard. The card chassis is fixed-width, so a flex parent is required for it to sit in the middle of the viewport; mirrors ViewLoading.root and the other system-view roots so deactivation reads as a sibling of the missing-route and slow-load surfaces. |
| ViewTwoFactorAuth | key | 5 | Outer wrapper. Empty; the embedded AuthorizingForm owns the framed card and viewport-centred chrome, so this key is left open as the consumer-facing override surface. |
| ViewSetupDevice | key | 13 | Horizontal stepper rail above the form body. mb-4 opens a 16 px gap between the rail and the first field so the progress indicator reads as supporting chrome, not the form's leading row. Used as the <ol> element so screen readers see the steps as a list; the consumer supplies aria-label="Setup progress". |
| ViewExecuteTransition | key | 1 | Outer wrapper around the embedded PageTitle and ModelActionForm. Empty by default; the two inner shells own all visible chrome, so this key exists only as the consumer-facing override surface and the data-qa anchor. |
| ViewRecoveryCodes | key | 12 | Outer wrapper. Empty; the embedded AuthForm owns the framed card chassis, and the slots inside it own all visible chrome. |
navigation
| Component | Kind | Slots | Description |
|---|---|---|---|
| Breadcrumb | key | 1 | Root context only. The trail's visible layout lives on BreadcrumbList.root. |
| BreadcrumbList | key | 1 | Inline wrapping row for breadcrumb items. |
| BreadcrumbItem | key | 1 | One breadcrumb step plus its separator affordance, sized as an inline cluster. |
| BreadcrumbLink | key | 1 | Navigable trail step. Hover and focus move toward foreground without changing weight. |
| BreadcrumbPage | key | 1 | Current-page trail step. Uses foreground colour, not heavier type, so the trail still reads as one line. |
| BreadcrumbSeparator | key | 1 | Separator glyph sizing. Default markup supplies a slash, while custom children can supply another glyph. |
| BreadcrumbEllipsis | key | 2 | Collapsed-step marker. The interactive state turns it into the dropdown trigger shape. |
| DropdownMenuGroup | key | 1 | Semantic grouping only. Item spacing and dividers are owned by child item and separator slots. |
| DropdownMenuRadioGroup | key | 1 | Semantic radio group only. Individual options own their indicator offset. |
| DropdownMenuTrigger | key | 1 | Unstyled trigger pass-through so callers can compose Button or custom trigger chrome. |
| DropdownMenuContent | key | 1 | Popover-like menu surface with bounded height, menu padding, and side-aware entrance motion. |
| DropdownMenuItem | key | 1 | Selectable menu row. Focus uses neutral accent, destructive rows tint text and focus fill without changing the surface recipe. |
| DropdownMenuCheckboxItem | key | 2 | Toggleable menu row with reserved indicator space at the leading edge. See also: DropdownMenuItem.root. |
| DropdownMenuRadioItem | key | 2 | Mutually exclusive menu row. Same layout as DropdownMenuCheckboxItem.root; selection state comes from the radio primitive. |
| DropdownMenuLabel | key | 1 | Non-interactive group label using the mono micro uppercase recipe. |
| DropdownMenuSeparator | key | 1 | Full-width menu divider that bleeds through the content padding. |
| DropdownMenuShortcut | key | 3 | Alignment wrapper for the trailing keyboard hint. The nested KbdGroup.root owns the chord. |
| DropdownMenuSubTrigger | key | 2 | Menu row that opens a child surface. Open and focused states share the same neutral accent fill. |
| DropdownMenuSubContent | key | 1 | Child popover surface for nested menu content. Mirrors DropdownMenuContent.root without the scroll height cap. |
| ContextMenuGroup | key | 1 | Semantic grouping only. See also: DropdownMenuGroup.root. |
| ContextMenuRadioGroup | key | 1 | Semantic radio group only. See also: DropdownMenuRadioGroup.root. |
| ContextMenuTrigger | key | 1 | Unstyled trigger pass-through for the element that owns the context-menu gesture. |
| ContextMenuContent | key | 1 | Context-menu surface. Matches DropdownMenuContent.root while using context-menu collision sizing. |
| ContextMenuItem | key | 1 | Selectable context-menu row. See also: DropdownMenuItem.root. |
| ContextMenuCheckboxItem | key | 2 | Toggleable context-menu row with reserved indicator space. See also: DropdownMenuCheckboxItem.root. |
| ContextMenuRadioItem | key | 2 | Radio-style context-menu row. See also: DropdownMenuRadioItem.root. |
| ContextMenuLabel | key | 1 | Non-interactive context-menu group label. See also: DropdownMenuLabel.root. |
| ContextMenuSeparator | key | 1 | Context-menu divider that bleeds through menu padding. See also: DropdownMenuSeparator.root. |
| ContextMenuShortcut | key | 3 | Alignment wrapper for context-menu command shortcuts. See also: DropdownMenuShortcut.root. |
| ContextMenuSubTrigger | key | 2 | Context-menu row that opens a child surface. See also: DropdownMenuSubTrigger.root. |
| ContextMenuSubContent | key | 1 | Child context-menu surface. See also: DropdownMenuSubContent.root. |
| MenubarGroup | key | 1 | Semantic grouping only inside menubar content. See also: DropdownMenuGroup.root. |
| MenubarRadioGroup | key | 1 | Semantic radio group only inside menubar content. See also: DropdownMenuRadioGroup.root. |
| Menubar | key | 1 | Horizontal menu bar surface. It keeps the popover/menu family language while the bar shadow stays flat. |
| MenubarTrigger | key | 1 | Top-level menubar trigger. Uses compact rounded corners and neutral accent open/focus states. |
| MenubarContent | key | 1 | Floating menu surface opened from the menubar. See also: DropdownMenuContent.root. |
| MenubarItem | key | 1 | Selectable menubar command row. See also: DropdownMenuItem.root. |
| MenubarCheckboxItem | key | 2 | Toggleable menubar row with reserved indicator space. Differs from dropdown by using the tighter menubar row radius. |
| MenubarRadioItem | key | 2 | Radio-style menubar row. Same row geometry as MenubarCheckboxItem.root. |
| MenubarLabel | key | 1 | Non-interactive menubar group label. See also: DropdownMenuLabel.root. |
| MenubarSeparator | key | 1 | Menubar content divider that bleeds through menu padding. See also: DropdownMenuSeparator.root. |
| MenubarShortcut | key | 3 | Alignment wrapper for the trailing keyboard hint inside menubar content. See also: DropdownMenuShortcut.root. |
| MenubarSubTrigger | key | 2 | Menubar row that opens a nested submenu. See also: DropdownMenuSubTrigger.root. |
| MenubarSubContent | key | 1 | Child menubar surface. See also: DropdownMenuSubContent.root. |
| NavigationMenu | key | 1 | Root flex context that centers the navigation menu and scopes viewport mode selectors. |
| NavigationMenuList | key | 1 | Top-level list row for navigation menu items, with reset list styling and compact gaps. |
| NavigationMenuItem | key | 1 | Positioning wrapper for one top-level navigation menu entry and its content. |
| NavigationMenuTrigger | key | 1 | Header-scale trigger. It intentionally uses a 36px height and half-strength active fill. |
| NavigationMenuContent | key | 1 | Panel content area with motion-aware slide transitions. When the viewport is disabled, this slot becomes its own popover surface. |
| NavigationMenuLink | key | 1 | Link row inside a navigation panel. Active uses bg-accent/50 so hover remains the stronger cue. |
| NavigationMenuIndicator | key | 2 | Animated indicator container that lines up the arrow between the trigger and open panel. |
| NavigationMenuViewport | key | 2 | Absolute wrapper that positions the shared viewport below the trigger row. |
| PaginationItem | key | 1 | Numbered page control. Composes the Button base and switches between outline active and ghost inactive variants. |
| NavigationPaginationNavButton | key | 1 | Previous, next, first, or last control. Icon-only, outline, compact (sm) square: composes the Button base and outline variant and pins a size-vueda-control-sm square so the four edge controls read as a dense, single-tier cluster. The accessible name rides an sr-only label in each SFC; the visible glyph comes from the icon registry. |
| PaginationContent | key | 1 | Compact row that groups page controls without owning their button chrome. |
| PaginationEllipsis | key | 1 | Omitted-page marker sized to align with neighboring pagination controls. |
| Pagination | key | 1 | Root pagination nav layout, centered across the available width. |
| NavigationPaginationBar | key | 1 | Footer bar for table and objects-grid pagination, seated against the bottom of card-like data surfaces. The px-5 py-3 padding matches the list chrome rhythm (e.g. ViewList.underActionsBar) so the chrome above and below the grid read as a matched frame. |
| PaginationMeta | key | 1 | Compact mono count text for page or record summaries. See also: NavigationPaginationBar.root. |
| PaginationFooter | key | 7 | Class forwarded to the embedded NavigationPaginationBar root. Empty by default: the bar supplies the footer chrome (border, surface, radius caps) and the inner PaginationFooter.layout owns the responsive arrangement. |
| SidebarContent | key | 1 | Scrollable main sidebar region. Icon-collapsed mode hides overflow so labels do not bleed past the rail. |
| SidebarFooter | key | 1 | Bottom sidebar section for account and secondary controls, using the same padding cadence as the header. |
| SidebarUserBlock | key | 5 | Horizontal account row for the sidebar footer. |
| SidebarGroupContent | key | 1 | Full-width body area for controls inside a sidebar group. |
| SidebarGroup | key | 1 | Section wrapper that provides local padding and positioning for group labels and actions. |
| SidebarHeader | key | 1 | Top sidebar section for brand, search, or primary navigation controls. |
| SidebarInput | key | 1 | Sidebar-local input chrome. It binds hairline and focus colors to sidebar tokens rather than generic input tokens. |
| SidebarMenuItem | key | 1 | Relative wrapper that scopes peer selectors for buttons, badges, and trailing actions. |
| SidebarMenuSub | key | 1 | Nested list rail and indentation for submenu items. Icon-collapsed mode hides the nested list. |
| SidebarMenuSubItem | key | 1 | Relative wrapper for one nested sidebar menu item. |
| SidebarMenu | key | 1 | Vertical menu list with narrow gaps for dense sidebar navigation. |
| SidebarGroupAction | key | 1 | Compact header action aligned to a group label. Hidden in icon-collapsed mode. |
| SidebarGroupLabel | key | 1 | Sidebar group heading using the page-level eyebrow recipe. |
| SidebarInset | key | 1 | Main content wrapper adjacent to the sidebar. Inset variant chrome exists in source but is not the admin-app default. |
| SidebarMenuBadge | key | 1 | Count or status badge anchored to a menu button. Tone handling stays local to sidebar tokens and hides in icon-collapsed mode. |
| SidebarRail | key | 1 | Edge hit target for toggling collapsed state. |
| SidebarSeparator | key | 1 | Full-bleed sidebar divider. It avoids inset hairlines so section breaks do not read as notches. |
| SidebarTrigger | key | 1 | Compact sidebar toggle button. The glyph is supplied through the icon registry. |
| SidebarMenuAction | key | 1 | Trailing menu-item action. showOnHover defers visibility until hover, focus-within, or open state on desktop. |
| SidebarMenuSubButton | key | 1 | Nested sidebar control. Active state paints the sidebar rail through Sidebar tokens.css-token:vueda-sidebar-active-rail. |
| SidebarMenuSkeleton | key | 1 | Placeholder menu row that aligns loading content with normal sidebar menu button geometry. |
| SidebarProvider | key | 1 | Layout wrapper that scopes sidebar state selectors and inset variant background behavior. |
| Sidebar | key | 3 | Uncollapsed sidebar body for the none collapsible mode. |
| SidebarMenuButtonChild | key | 1 | Primary sidebar menu button content. Active state uses a rail and icon tint, not a type-weight bump, so hover does not shift label width. |
display
| Component | Kind | Slots | Description |
|---|---|---|---|
| AspectRatio | key | 1 | Empty pass-through wrapper for ratio-bound media; sizing comes from the primitive and caller. |
| DateRangeDisplay | key | 4 | Inline date-range wrapper that prevents the paired dates and separator from wrapping apart. |
| DateTimeDisplay | key | 7 | Inline time wrapper with baseline spacing for absolute and relative text. |
| ErrorDisplay | key | 5 | Full-width error block wrapper for message, code, and links. |
| ClickToCopyText | key | 1 | Baseline row for a compact read-only value and its copy affordance. |
| Badge | key | 1 | Compact slab badge with variant and numeric recipes. |
| Kbd | key | 1 | Single keycap chip for shortcut hints; tooltip nesting adjusts contrast. |
| KbdGroup | key | 1 | Inline shortcut sequence wrapper that clusters adjacent Kbd.root chips into one chord. |
| Avatar | key | 1 | Circular clipping frame shared by avatar image and fallback content. |
| AvatarImage | key | 1 | Square image fill that inherits clipping from Avatar.root. |
| AvatarFallback | key | 1 | Centered muted fallback surface for initials or placeholder content. |
| UserAvatar | key | 2 | Initials chip frame. The component supplies size inline from its size prop, while tone selects the primary or sidebar color recipe. |
| ConsequencesBullets | key | 8 | List wrapper for consequence rows with no browser list chrome. |
| SystemMessageCard | key | 9 | Centered card chassis with the named tone group used by crest descendants. |
| LoadingHeartbeatStrip | key | 5 | Mono status row that separates request identity from live loading state. |
| LoadingSkeletonGhost | key | 2 | Bordered placeholder card with the shimmer overlay owned by this loading preview. |
| DiagnosticStrip | key | 3 | Compact diagnostic definition-list grid for request, route, or session values. |
| SuggestionList | key | 13 | Outer suggestion stack; border treatment lives on SuggestionList.list. |
| TriedUrlCallout | key | 4 | Two-column callout wrapper for the attempted URL. |
| ResponsiveMenu | key | 3 | Full-screen mobile dialog surface with a fixed header row and a bounded body row. |
| FieldPickerMenuList | key | 4 | Eyebrow at the top of the field-picker list. The in-popover micro-eyebrow recipe (11 px / 600 / 0.04em). |
| ConstraintsBar | key | 4 | Collapse wrapper. A grid-template-rows animation (0fr to 1fr) reveals or hides the band at the canonical interaction duration; the SFC sets the row value inline. Disabled under reduced-motion. |
| SortChip | key | 9 | Pill container. Neutral surface with a strong hairline so it reads against both the card and the constraints-strip tint. |
| SortGroup | key | 6 | Active-sort chips strip. A sunken tint a tier below the card so it reads as a distinct band from the primary-tinted filter strip above it. Shares the page-chrome rhythm and carries a bottom hairline. |
feedback
| Component | Kind | Slots | Description |
|---|---|---|---|
| Alert | key | 1 | The outer alert surface and layout grid. It owns the optional icon column, card radius, and semantic status recipe, with variant colors flowing into AlertDescription.root. |
| AlertClose | key | 1 | The positioned dismiss affordance for closable alerts. It stays visually quiet until hover or keyboard focus, then uses the shared ring color through the focus-visible outline. |
| AlertTitle | key | 1 | The primary message heading inside the alert grid. It starts in the content column created by Alert.root and clamps to one line so status banners do not grow from long labels. |
| AlertDescription | key | 1 | The supporting message copy beneath the alert title. It inherits variant-specific description tint from Alert.root while keeping nested paragraphs readable for short remediation text. |
| AlertActions | key | 1 | The inline action row for alert follow-up controls. It shares the alert content column with AlertTitle.root and AlertDescription.root, so buttons align under the message instead of under the icon. |
| Progress | key | 2 | The progress track surface and clipping frame. It sets the canonical 8px default height, optional compact or large heights, and status track tints. |
| Skeleton | key | 1 | The loading placeholder block. The primary tint stays neutral enough for rows, cards, and inline placeholders. |
| Sonner | key | 1 | The toast viewport theme hook passed to vue-sonner. It establishes the toaster group while toast surface, type tint, and icon resolution stay controlled by the wrapper component and Sonner rules. |