Form Components
Select
Select presents a list of options using the native dropdown, so it stays keyboard and screen-reader correct and behaves as expected on mobile.
Basic usage
Select renders a real <select>, so keyboard support, screen-reader semantics, form submission and constraint validation all come from the platform rather than from re-implemented JavaScript.
<Select> <option>Cyprus</option> <option>Estonia</option> <option>Portugal</option></Select>The native arrow is replaced with a themed chevron that scales with the size prop. The field reserves room for it, so a long option never runs underneath. The selected value stays on one line, and at the same size a Select is as tall as an Input or a Button. In a Row, noShrink keeps the Select at its natural width.
The dropdown list
Historically a native <select> hands its option list to the operating system, which draws a flat, square, unpadded menu that no page CSS can reach. Only the option's text and background colour land, because the options get no layout box at all.
On engines that support appearance: base-select the list becomes real DOM instead, and VaneUI styles it to match a Menu: themed surface, border, radius, shadow, padded rows, a hover state, and a checkmark on the selected option. Everywhere else the OS picker still appears, with option and optgroup carrying the field's surface and text colours so the list at least stays on your palette in both light and dark mode.
The list opens below the field and flips above it only when it genuinely does not fit. Browsers default to whichever side has more room, which sends the list upward for any field past the middle of the window even when there is space below it.
Options are children of the field, so they inherit its colours: the list follows the appearance and variant you set rather than staying pinned to the light surface. A disabled option, typically a placeholder, fades toward the list's own background instead of a fixed grey, so it stays readable on a filled list too.
Nothing is required to opt in, and nothing breaks on engines without it: the enhancement sits behind an @supports rule and the control is the same <select> either way.
Sizes
Selects come in five sizes: xs, sm, md (default), lg, xl. The chevron and the room reserved for it scale with the field.
<Col> <Select xs defaultValue="sm"> <option value="xs">Extra small</option> <option value="sm">Small</option> <option value="md">Medium</option> <option value="lg">Large</option> </Select> <Select sm defaultValue="sm"> <option value="xs">Extra small</option> <option value="sm">Small</option> <option value="md">Medium</option> <option value="lg">Large</option> </Select> <Select defaultValue="sm"> <option value="xs">Extra small</option> <option value="sm">Small</option> <option value="md">Medium</option> <option value="lg">Large</option> </Select> <Select lg defaultValue="sm"> <option value="xs">Extra small</option> <option value="sm">Small</option> <option value="md">Medium</option> <option value="lg">Large</option> </Select> <Select xl defaultValue="sm"> <option value="xs">Extra small</option> <option value="sm">Small</option> <option value="md">Medium</option> <option value="lg">Large</option> </Select></Col>States
invalid adds a danger border and ring, turns the chevron danger, and emits aria-invalid. Pair it with Field to attach the message.
<Col> <Select defaultValue="eur"> <option value="eur">Euro</option> <option value="usd">US dollar</option> <option value="gbp">Pound sterling</option> </Select> <Select invalid defaultValue=""> <option value="" disabled>Select a currency</option> <option value="eur">Euro</option> <option value="usd">US dollar</option> <option value="gbp">Pound sterling</option> </Select> <Select disabled defaultValue="eur"> <option value="eur">Euro</option> <option value="usd">US dollar</option> <option value="gbp">Pound sterling</option> </Select></Col>Appearances
Selects are primary by default and take the same appearance props as Input.
<Row flexWrap> <Select className="w-40" defaultValue="eur"> <option value="eur">Primary</option> <option value="usd">US dollar</option> </Select> <Select success className="w-40" defaultValue="eur"> <option value="eur">Success</option> <option value="usd">US dollar</option> </Select> <Select warning className="w-40" defaultValue="eur"> <option value="eur">Warning</option> <option value="usd">US dollar</option> </Select> <Select danger className="w-40" defaultValue="eur"> <option value="eur">Danger</option> <option value="usd">US dollar</option> </Select></Row>Variants
outline is the default. The dropdown list takes its colours from the field, so a filled Select opens a filled list rather than a light one on a dark control. ghost drops the field's own surface but keeps the list opaque, since a see-through popup would render the options unreadable.
<Row flexWrap> <Select className="w-40" defaultValue="eur"> <option value="eur">Outline</option> <option value="usd">US dollar</option> </Select> <Select filled className="w-40" defaultValue="eur"> <option value="eur">Filled</option> <option value="usd">US dollar</option> </Select> <Select ghost className="w-40" defaultValue="eur"> <option value="eur">Ghost</option> <option value="usd">US dollar</option> </Select></Row>Shapes
rounded is the default, and the shape carries through to the dropdown: a sharp Select opens a sharp list rather than a rounded one on a square field.
pill is the exception. It reshapes the field only, because a pill radius is effectively infinite and a tall list box given that radius swallows its own first and last rows.
<Row flexWrap> <Select rounded className="w-40" defaultValue="eur"> <option value="eur">Rounded</option> <option value="usd">US dollar</option> </Select> <Select pill className="w-40" defaultValue="eur"> <option value="eur">Pill</option> <option value="usd">US dollar</option> </Select> <Select sharp className="w-40" defaultValue="eur"> <option value="eur">Sharp</option> <option value="usd">US dollar</option> </Select></Row>Groups and placeholders
Sets your default currency.
<Field label="Region" description="Sets your default currency."> <Select defaultValue=""> <option value="" disabled>Choose a region</option> <optgroup label="Europe"> <option>Cyprus</option> <option>Estonia</option> </optgroup> <optgroup label="Americas"> <option>Canada</option> </optgroup> </Select></Field>Select Props
| Prop | Category | Default | Description |
|---|---|---|---|
accent | Appearance | Accent color appearance (rose) | |
danger | Appearance | Danger color appearance (red) | |
info | Appearance | Info color appearance (cyan) | |
inheritAppearance | Appearance | Inherit appearance from parent — suppresses own data-appearance/data-variant, uses parent's CSS variables | |
primary | Appearance | ✓ | Primary color appearance (gray) |
secondary | Appearance | Secondary color appearance (gray) | |
success | Appearance | Success color appearance (green) | |
tertiary | Appearance | Tertiary color appearance | |
warning | Appearance | Warning color appearance (amber) | |
disabled | Disabled | Disable the component — reduces opacity, changes cursor to not-allowed, and prevents interaction | |
flex1 | Flex | Take up remaining space (= | |
flexAuto | Flex | Grow but respect intrinsic size (= | |
flexNone | Flex | Don't grow and don't shrink (= | |
fontHeading | Font Family | Heading font family (defaults to sans, customizable via --font-heading) — emits font-heading | |
fontMono | Font Family | Monospace font family — emits font-mono | |
fontSans | Font Family | ✓ | Sans-serif font family (default) — emits font-sans |
fontSerif | Font Family | Serif font family — emits font-serif | |
italic | Font Style | Italic font style | |
notItalic | Font Style | Not italic (normal) font style | |
fontBlack | Font Weight | Black font weight (900) — emits font-black | |
fontBold | Font Weight | Bold font weight (700) — emits font-bold | |
fontExtrabold | Font Weight | Extra bold font weight (800) — emits font-extrabold | |
fontExtralight | Font Weight | Extra light font weight (200) — emits font-extralight | |
fontLight | Font Weight | Light font weight (300) — emits font-light | |
fontMedium | Font Weight | Medium font weight (500) — emits font-medium | |
fontNormal | Font Weight | ✓ | Normal font weight (400) — emits font-normal |
fontSemibold | Font Weight | Semibold font weight (600) — emits font-semibold | |
fontThin | Font Weight | Thin font weight (100) — emits font-thin | |
noPadding | Padding | Disable internal padding | |
padding | Padding | ✓ | Enable internal padding |
paddingX | Padding | Enable only horizontal padding | |
paddingY | Padding | Enable only vertical padding | |
readOnly | Read Only | Render the field read-only — mutes it (lighter than disabled) and sets a default cursor; the value stays selectable and submittable | |
pill | Shape | Fully rounded corners (circular) | |
rounded | Shape | ✓ | Medium rounded corners (default) |
sharp | Shape | No rounded corners (square) | |
noShrink | Shrink | Prevent the flex item from shrinking below its content size (= | |
lg | Size | Large size | |
md | Size | ✓ | Medium size (default) |
sm | Size | Small size | |
xl | Size | Extra large size | |
xs | Size | Extra small size | |
textCenter | Text Align | Align text to center | |
textEnd | Text Align | Align text to the reading-direction end (right in LTR, left in RTL) | |
textJustify | Text Align | Justify text | |
textLeft | Text Align | Align text to left (physical side, does not flip under RTL) | |
textRight | Text Align | Align text to right (physical side, does not flip under RTL) | |
textStart | Text Align | Align text to the reading-direction start (left in LTR, right in RTL) | |
lineThrough | Text Decoration | Add strikethrough/line-through decoration across text | |
noUnderline | Text Decoration | Remove ALL text-decoration — underline, line-through, and overline (text-decoration: none) | |
overline | Text Decoration | Add overline decoration above text | |
underline | Text Decoration | Add underline decoration below text | |
capitalize | Text Transform | Capitalize first letter of each word | |
lowercase | Text Transform | Transform text to lowercase | |
normalCase | Text Transform | Normal text case (no transformation) | |
uppercase | Text Transform | Transform text to uppercase | |
lineClamp2 | Truncate | Truncate at 2 lines with ellipsis | |
lineClamp3 | Truncate | Truncate at 3 lines with ellipsis | |
lineClamp4 | Truncate | Truncate at 4 lines with ellipsis | |
lineClamp5 | Truncate | Truncate at 5 lines with ellipsis | |
noTruncate | Truncate | Remove truncation | |
truncate | Truncate | Single line truncation with ellipsis | |
invalid | Validity | Mark the field invalid (red border/ring), layered over any appearance | |
filled | Variant | Filled variant - solid background with contrasting text color | |
ghost | Variant | Ghost variant - transparent background, no border, appearance-colored text, tinted hover background | |
outline | Variant | ✓ | Outline variant - transparent background with border and colored text (default) |
Layout & utility props (gap, padding, hide, items, justify, ...) — documented on Common Props
| Prop | Category | Default | Description |
|---|---|---|---|
border | Border | Enable border on all sides | |
borderB | Border | Enable border on bottom | |
borderEnd | Border | Enable border on the inline-end side (right in LTR, left in RTL) | |
borderL | Border | Enable border on left | |
borderR | Border | Enable border on right | |
borderStart | Border | Enable border on the inline-start side (left in LTR, right in RTL) | |
borderT | Border | Enable border on top | |
borderX | Border | Enable border on left and right | |
borderY | Border | Enable border on top and bottom | |
noBorder | Border | Disable all borders | |
cursorDefault | Cursor | Default cursor - standard arrow | |
cursorMove | Cursor | Move cursor - indicates draggable element | |
cursorNone | Cursor | No cursor - hides the cursor | |
cursorNotAllowed | Cursor | Not-allowed cursor - indicates disabled state | |
cursorPointer | Cursor | ✓ | Pointer cursor - indicates clickable element |
cursorText | Cursor | Text cursor - indicates selectable text | |
cursorWait | Cursor | Wait cursor - indicates loading/processing | |
block | Display | Block display - takes full width, new line | |
contents | Display | Contents display - element's box is removed, children display as if parent didn't exist | |
flex | Display | Flex display - flexbox container | |
grid | Display | Grid display - CSS grid container | |
hidden | Display | Hidden display - element is not visible | |
inline | Display | Inline display - flows with text | |
inlineBlock | Display | Inline-block display - inline but with block properties | |
inlineFlex | Display | Inline-flex display - inline flexbox container | |
inlineGrid | Display | Inline-grid display - inline grid container | |
table | Display | Table display - behaves like table element | |
tableCell | Display | Table-cell display - behaves like td element | |
column | Flex Direction | Flex direction column (vertical) | |
columnReverse | Flex Direction | Flex direction column-reverse | |
row | Flex Direction | Flex direction row (horizontal) | |
rowReverse | Flex Direction | Flex direction row-reverse | |
focusVisible | Focus Visible | ✓ | Enable focus-visible outline |
noFocusVisible | Focus Visible | Disable focus-visible outline | |
gap | Gap | Enable gap spacing between children | |
noGap | Gap | Disable gap spacing | |
hAuto | Height | Set height to auto | |
hFit | Height | Set height to fit-content | |
hFull | Height | Set height to 100% | |
hScreen | Height | Set height to 100vh (viewport height), removes max-height constraint | |
desktopHide | Hide | Hide element on desktop devices and below (max-desktop: 80rem) | |
mobileHide | Hide | Hide element on mobile devices and below (max-mobile: 48rem) | |
tabletHide | Hide | Hide element on tablet devices and below (max-tablet: 64rem) | |
itemsBaseline | Items | Align items to baseline | |
itemsCenter | Items | Align items to center | |
itemsEnd | Items | Align items to end (bottom/right) | |
itemsStart | Items | Align items to start (top/left) | |
itemsStretch | Items | Stretch items to fill container | |
justifyAround | Justify | Distribute items with space around them | |
justifyBaseline | Justify | Align items along their baseline on main axis | |
justifyBetween | Justify | Distribute items with space between them | |
justifyCenter | Justify | Center items along the main axis | |
justifyEnd | Justify | Pack items toward the end of the main axis | |
justifyEvenly | Justify | Distribute items with equal space around them | |
justifyStart | Justify | Pack items toward the start of the main axis | |
justifyStretch | Justify | Stretch items to fill the main axis | |
overflowAuto | Overflow | Auto overflow - show scrollbars if needed | |
overflowClip | Overflow | Clip overflow - hard clip without scrollbars | |
overflowHidden | Overflow | Hidden overflow - clip content without scrollbars | |
overflowScroll | Overflow | Scroll overflow - always show scrollbars | |
overflowVisible | Overflow | Visible overflow - content extends beyond bounds | |
overflowXAuto | Overflow | Auto overflow on X-axis only | |
overflowXClip | Overflow | Clip overflow on X-axis only | |
overflowXHidden | Overflow | Hidden overflow on X-axis only | |
overflowXScroll | Overflow | Scroll overflow on X-axis only | |
overflowXVisible | Overflow | Visible overflow on X-axis only | |
overflowYAuto | Overflow | Auto overflow on Y-axis only | |
overflowYClip | Overflow | Clip overflow on Y-axis only | |
overflowYHidden | Overflow | Hidden overflow on Y-axis only | |
overflowYScroll | Overflow | Scroll overflow on Y-axis only | |
overflowYVisible | Overflow | Visible overflow on Y-axis only | |
absolute | Position | Absolute positioning | |
fixed | Position | Fixed positioning | |
relative | Position | Relative positioning | |
static | Position | Static positioning | |
sticky | Position | Sticky positioning | |
responsiveSizing | Responsive Sizing | Enable responsive sizing - uses breakpoint-specific classes for font size, padding, and gap | |
insetRing | Ring | ✓ | Enable the inset ring — emits ring-inset |
noInsetRing | Ring | Disable the inset ring | |
noShadow | Shadow | ✓ | Disable drop shadow |
shadow | Shadow | Enable drop shadow | |
noTransition | Transition | Disable transitions for instant state changes | |
transition | Transition | ✓ | Enable smooth transitions between states |
transparent | Transparent | Disable background color - makes component background transparent | |
whitespaceBreakSpaces | Whitespace | Preserve whitespace incl. trailing spaces, wrap text (white-space: break-spaces) | |
whitespaceNormal | Whitespace | Normal wrapping - default browser behavior | |
whitespaceNowrap | Whitespace | No wrap - text stays on single line | |
whitespacePre | Whitespace | Preserve whitespace and line breaks | |
whitespacePreLine | Whitespace | Preserve line breaks, collapse spaces, wrap text | |
whitespacePreWrap | Whitespace | Preserve whitespace, wrap text | |
wAuto | Width | Set width to auto | |
wFit | Width | Set width to fit-content | |
wFull | Width | ✓ | Set width to 100% |
wScreen | Width | Set width to 100vw (viewport width), removes max-width constraint | |
flexNoWrap | Wrap | Force flex items to stay on single line (may overflow) | |
flexWrap | Wrap | Allow flex items to wrap to new lines when container is too narrow | |
flexWrapReverse | Wrap | Wrap flex items in reverse order (last items wrap first) |