Skip to content

controls keys

Source file: client/lib/theme/vueda-tailwind/controls/index.js

Button family meta keys

ComponentKindSlotsDescription
_ButtonBaseprimitive1The 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.
_ButtonDefaultprimitive1The --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.
_ButtonDestructiveprimitive1The --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.
_ButtonOutlineprimitive1The 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.
_ButtonSecondaryprimitive1The --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.
_ButtonGhostprimitive1The 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.
_ButtonLinkprimitive1The 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.
_ButtonPrimaryOutlineprimitive1The 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.
_ButtonDestructiveOutlineprimitive1The 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).
_ButtonPrimaryGhostprimitive1The 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.
_ButtonDestructiveGhostprimitive1The 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.
_ButtonNeutralLinkprimitive1The 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.
_ButtonDestructiveLinkprimitive1The 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

ComponentKindSlotsDescription
Buttonkey1The 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.

Button group

ComponentKindSlotsDescription
ButtonGroupkey1The 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.
ButtonGroupSeparatorkey1The 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.
ButtonGroupTextkey1The 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

ComponentKindSlotsDescription
Togglekey1The 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.
ToggleGroupkey1The 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.
ToggleGroupItemkey1The 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.

File upload

ComponentKindSlotsDescription
FileUploadkey3The 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.

Text input

ComponentKindSlotsDescription
Inputkey1The 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.
Textareakey1The 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.

Input group

ComponentKindSlotsDescription
InputGroupkey1The 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.
InputGroupAddonkey1The 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.
InputGroupInputkey1The 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.
InputGroupTextareakey1The 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.
InputGroupTextkey1The 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.
InputGroupButtonkey1Pressable 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.

Input OTP

ComponentKindSlotsDescription
InputOTPkey1The 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.
InputOTPGroupkey1A 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.
InputOTPSlotkey1A 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.

Native select

ComponentKindSlotsDescription
NativeSelectkey1The 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.
NativeSelectOptGroupkey1The 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.
NativeSelectOptionkey1The 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.

Number field

ComponentKindSlotsDescription
NumberFieldkey1The 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.
NumberFieldContentkey1The 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.
NumberFieldInputkey1The 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.
NumberFieldDecrementkey1The 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.
NumberFieldIncrementkey1The increment stepper anchored to the right edge of NumberFieldInput.root. Mirror of NumberFieldDecrement.root; same overlay positioning and same upper-bound fade.

Date / time fields

ComponentKindSlotsDescription
DateFieldkey1The 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.
DateFieldInputkey1A 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.
DateRangeFieldkey1The 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.
DateRangeFieldInputkey1An editable segment inside a DateRangeField.root. See also: DateFieldInput.root; same mono + tabular + slashed-zero, accent-on-focus, caret-transparent recipe applies.
TimeFieldkey1The 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.
TimeFieldInputkey1An editable segment inside a TimeField.root. See also: DateFieldInput.root; identical recipe.

Calendar

ComponentKindSlotsDescription
Calendarkey1The 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.
CalendarHeaderkey1The 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.
CalendarHeadingkey1The month-year title text inside a CalendarHeader.root. Single-line text-sm font-medium; sits centred between the prev / next nav buttons.
CalendarNavButtonkey1The 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.
CalendarGridkey1The 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.
CalendarGridRowkey1A single week row inside a CalendarGrid.root. Flex row; cell width comes from flex-1 on the children, not from a column template.
CalendarHeadCellkey1A 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.
CalendarCellkey1A 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.
CalendarCellTriggerkey1The 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.
CalendarFooterkey2The 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.

Range calendar

ComponentKindSlotsDescription
RangeCalendarkey1See also: Calendar.root; identical 12px-padded surface, only the grid inside differs (the RangeCalendarCell.root carries the range-fill state).
RangeCalendarHeaderkey1The 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.
RangeCalendarHeadingkey1See also: CalendarHeading.root; identical recipe.
RangeCalendarPrevButtonkey1The 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.
RangeCalendarNextButtonkey1See also: RangeCalendarPrevButton.root; mirror anchored to the right edge of the header at right-1.
RangeCalendarGridkey1See also: CalendarGrid.root; identical recipe.
RangeCalendarGridRowkey1See also: CalendarGridRow.root; identical recipe.
RangeCalendarHeadCellkey1See also: CalendarHeadCell.root; identical recipe (the class-order difference vs the single-calendar slot is incidental, not a deliberate departure).
RangeCalendarCellkey1A 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.
RangeCalendarCellTriggerkey1The 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.

Combobox

ComponentKindSlotsDescription
ComboboxAnchorkey1The 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.
ComboboxTriggerkey1The 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.
ComboboxListkey1The 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.
ComboboxViewportkey1The 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.
ComboboxInputkey1The 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.
ComboboxGroupkey2A 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.
ComboboxItemkey1A 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.
ComboboxItemIndicatorkey1The 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.
ComboboxSeparatorkey1A 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.
ComboboxEmptykey1The 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

ComponentKindSlotsDescription
Commandkey1The 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.
CommandInputkey2The 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.
CommandListkey1The 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.
CommandEmptykey1The zero-result placeholder shown inside CommandList.root when the search has no matches. See also: ComboboxEmpty.root; identical recipe.
CommandGroupkey2A section of related CommandItem.root rows inside CommandList.root. See also: ComboboxGroup.root; identical recipe.
CommandItemkey1A 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.
CommandSeparatorkey1A 1px horizontal divider between groups inside CommandList.root. See also: ComboboxSeparator.root; identical recipe.
CommandShortcutkey3Alignment 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.
CommandFooterkey3The 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.
CommandDialogkey2The 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.

Select

ComponentKindSlotsDescription
SelectTriggerkey1The 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.
SelectContentkey2The 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.
SelectItemkey1A 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.
SelectLabelkey1The 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).
SelectSeparatorkey1A 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.
SelectScrollUpButtonkey1The 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.
SelectScrollDownButtonkey1See also: SelectScrollUpButton.root; mirror at the bottom of the viewport.

Tags input

ComponentKindSlotsDescription
TagsInputkey1The 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.
TagsInputInputkey1The 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.
TagsInputItemkey1An 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.
TagsInputItemTextkey1The 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.
TagsInputItemDeletekey1The 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

ComponentKindSlotsDescription
Checkboxkey2The 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).

Radio group

ComponentKindSlotsDescription
RadioGroupkey1Layout 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.
RadioGroupItemkey3The 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

ComponentKindSlotsDescription
Switchkey2The 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

ComponentKindSlotsDescription
Sliderkey4The 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.

Documents matching: server v3.0.0a1.post1client v3.0.0-alpha.2