Skip to content

Inputs

The input family covers every text-entry, selection, and toggleable form control: labels, plain inputs, textareas, native selects, number fields, checkboxes, radio groups, tags inputs, and the OTP slot composer. They share the same control sizing as buttons (32 / 28 / 40 governed by Control sizing (VUEDA canon) tokens.css-token:vueda-control-height and its sm / lg companions) and the same focus treatment (2 px solid Color palette: light tokens.css-token:ring outline at 2 px offset). Border colors come from Color palette: light tokens.css-token:border and Color palette: light tokens.css-token:input; invalid states swap the outline to Color palette: light tokens.css-token:destructive.

This page is the visual contract the default theme guarantees. Use it as the target spec when you re-skin: every cell shown here should still read as the same control after a customization, even if its color, radius, or density shifts. If a cell breaks, the change has crossed from skin into design language.

For the mechanics of overriding any of this, see Customize VUEDA Appearance. In brief: values (color, dimension, duration) belong in CSS tokens; compositions (class arrangements, state recipes) belong in theme keys.

Two corners worth flagging up front. The checkbox body uses Semantic radius tokens.css-token:vueda-checkbox-radius (4 px) rather than the 2 px slab Semantic radius tokens.css-token:vueda-control-radius so a 16 × 16 box reads as a chiclet next to the slab inputs and buttons it sits beside in a form. And the focus ring is rendered as a real outline, not a box-shadow sandwich, so it sits outside the border-box without seam artifacts at sharp 2 px corners.

Label

Label is a typographic primitive paired with a focusable control. The interesting axes are content (text alone, text with an icon) and pairing (with an enabled control versus a disabled one, where peer-disabled:opacity-50 cascades the dimmed treatment from the sibling input).

Theme key: Label. Typography reads from Typography tokens.css-token:vueda-text-body (13 px) at weight 500.

Input: state matrix

The state cube for plain inputs is the validation axis (default, invalid), the read mode (read/write, readonly, disabled), and the type axis (text, password, file). Focus is reproduced via the docs harness so the ring is visible without keyboard interaction; hover has no dedicated treatment in the default theme for this control.

Theme key: Input. Token surface: Color palette: light tokens.css-token:input (border), Color palette: light tokens.css-token:background (fill), Color palette: light tokens.css-token:ring (focus outline), Color palette: light tokens.css-token:destructive (invalid outline), Color palette: light tokens.css-token:muted (read-only fill).

Textarea: state matrix

Textarea shares Input's border, focus, and invalid behavior; the only difference is height. The default theme uses field-sizing-content so the box grows with its content rather than scrolling internally.

Theme key: Textarea. Token surface mirrors Input.

NativeSelect: state matrix

NativeSelect wraps a real <select> element with a custom chevron icon overlay so the chrome reads consistently across operating systems. The chevron sits inside the component template, not the consumer's markup.

Theme keys: NativeSelect, NativeSelectOption, NativeSelectOptGroup. The chevron color reads from Color palette: light tokens.css-token:muted-foreground at 50% opacity.

NumberField: state matrix

NumberField composes an input with paired decrement/increment buttons. The three sub-components all carry their own theme keys; the wrapper handles positioning of the steppers inside the input box.

Theme keys: NumberField, NumberFieldContent, NumberFieldDecrement, NumberFieldIncrement, NumberFieldInput. Numerals render as tabular-nums so columns of values stay aligned.

Checkbox: state matrix

Checkbox has a tri-state model (unchecked, checked, indeterminate) plus the standard focus / disabled / invalid axes. The check and minus glyphs ship as default slot content; consumers can override the indicator slot to use icon components instead of text glyphs.

Theme key: Checkbox. The body is a 16 × 16 chiclet at Semantic radius tokens.css-token:vueda-checkbox-radius (4 px), intentionally rounder than the 2 px slab Semantic radius tokens.css-token:vueda-control-radius so the box reads as a chit rather than a miniature input next to its label.

RadioGroup: state matrix

RadioGroup is a controlled selection of mutually exclusive items; each item composes its own per-state appearance from the same scaffolding as Checkbox. The group itself only contributes layout (gap, orientation).

Theme keys: RadioGroup, RadioGroupItem. The selected dot is a geometric circle inside the item, not a glyph, so it stays stable across font hydration.

TagsInput: composition matrix

TagsInput is a chip container with a trailing input. The composition axis is content (with chips, empty, full to invalid, disabled across the whole field). Per-chip focus is shown via data-state="active" on the item; a focused chip gets the same outline ring as the focused container, just scoped to the chip.

Theme keys: TagsInput, TagsInputItem, TagsInputItemText, TagsInputItemDelete, TagsInputInput. Chips read at Specialized control sizes tokens.css-token:vueda-chip-height (20 px), the fourth step of the control-height ladder below sm.

InputOTP: composition matrix

InputOTP composes a row of single-character slots, optionally separated into groups by a glyph. The interesting axis is composition (single group, multiple groups with separator) and state (resting, partially filled, invalid, disabled). The active slot's caret animation reads from the --animate-caret-blink token, which drives the caret-blink keyframes inlined at the base layer.

Theme keys: InputOTP, InputOTPGroup, InputOTPSlot. Slots compose into the same border / focus surface as Input, with adjacent slots sharing seams via first:rounded-l-md / last:rounded-r-md rules.

Slider

Slider is a track with one or more draggable thumbs, bound through v-model to an array of numbers. One entry renders one thumb, so the same component covers a single value and a range; the filled range segment spans from the track start to the thumb, or between two thumbs.

step quantises the value and min-steps-between-thumbs stops two thumbs from crossing. The component reports its value continuously as the thumb moves; it does not debounce, so a consumer driving a request off it should do that itself.

Slider measures its track, so it needs a real layout pass and is wrapped in <ClientOnly> here. That is a documentation detail rather than a usage rule: an application renders it normally.

Theme keys: Slider. Token surface: Color palette: light tokens.css-token:primary (range fill), Color palette: light tokens.css-token:muted (track), Color palette: light tokens.css-token:ring (thumb focus).

InputGroup

InputGroup welds addons onto one control so the group reads as a single field: the group owns the border, radius, and focus ring, and the inner control renders without its own shell. Put an InputGroupInput or InputGroupTextarea inside, then any number of InputGroupAddons around it.

align places an addon: inline-start and inline-end sit beside the control on the same row, block-start and block-end sit above and below it. An addon holds whatever you give it, and the family ships two ready pieces: InputGroupText for static labels, prefixes, and units, and InputGroupButton for a pressable action (a ghost xs button by default, so it fits the row without competing with it).

Theme keys: InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, InputGroupButton, InputGroupTextarea.

FileUpload

FileUpload wraps a hidden native file input with a styled trigger reading "Choose file", and emits the chosen File through v-model. accept filters what the picker offers and max-file-size (bytes, default 1,000,000) rejects an oversized selection. dropzone adds a drop target around the trigger.

The component is a selection surface only. Choosing a file hands your code a File object from the browser; nothing is transmitted, stored, or authorised until the application sends it. accept and max-file-size are client-side conveniences the browser and the component apply, so a server still has to validate type and size itself.

Theme keys: FileUpload.

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