Component

Listbox

<dom-listbox>

A styled select-like list without text entry.

Playground

Try every prop live

Listbox playground

Use this when users choose from visible options and should not type arbitrary text.

Playground.vuevue
<script setup>
import { reactive } from 'vue';
import { DomListbox } from '@getdom/studio/vue';

const data = reactive({
	  "modelValue": "medium",
	  "id": "",
	  "name": "",
	  "label": "",
	  "description": "",
	  "placeholder": "",
	  "required": false,
	  "disabled": false,
	  "readOnly": false,
	  "invalid": false,
	  "errors": {},
	  "visible": true,
	  "validators": [],
	  "validateOnBlur": true,
	  "chrome": "field",
	  "options": [
	    {
	      "value": "small",
	      "label": "Small"
	    },
	    {
	      "value": "medium",
	      "label": "Medium"
	    },
	    {
	      "value": "large",
	      "label": "Large"
	    }
	  ],
	  "orientation": "vertical"
	});
</script>

<template>
	<DomListbox
		v-bind="data"
		@update:modelValue="data.modelValue = $event"
	/>
</template>

Demo

Custom option markup

The option slot can render richer labels while v-model remains the option value.

Selected value: team

Plan.vuevue
<script setup>
import { ref } from 'vue';
import { DomListbox } from '@getdom/studio/vue';

const value = ref('team');
const options = [
	{ value: 'solo', label: 'Solo', description: 'For small personal projects.' },
	{ value: 'team', label: 'Team', description: 'Shared workspace and billing.' },
	{ value: 'enterprise', label: 'Enterprise', description: 'SSO, audit logs, and support.' },
];
</script>

<template>
	<div class="grid w-full max-w-md gap-3">
		<DomListbox v-model="value" :options="options">
			<template #option="{ option }">
				<span class="block font-medium">{{ option.label }}</span>
				<span class="block text-xs opacity-75">{{ option.description }}</span>
			</template>
		</DomListbox>
		<p class="text-xs text-muted-fg">Selected value: <code class="text-fg">{{ value }}</code></p>
	</div>
</template>

Reference

Props

Control props

NameTypeTSDefaultDescription
modelValuestring | numberstring''Selected option value.
options*
[
	{
		label: "Option 1",
		value: "option-1",
	}
]
arrayArray<OptionsItem
type OptionsItem = {
	label?: string; // Label
	value?: string; // Value
};
>
Available options.
orientation'vertical' | 'horizontal'string'vertical'Arrow key direction.

Field props

NameTypeTSDefaultDescription
idstringstring''Optional ID override. By default parent forms derive the input ID from the field path using underscores.
namestringstring''Local field name. Parent forms derive the full field path and native HTML name from the form hierarchy.
labelstringstring''Visible field label.
descriptionstringstring''Optional helper copy below the field.
placeholderstringstring''Placeholder shown when the control is empty.
requiredbooleanbooleanfalseMark the field as required.
disabledbooleanbooleanfalseDisable field interaction.
readOnlybooleanbooleanfalseShow the value but prevent editing.
invalidbooleanbooleanfalseMark the field invalid.
errors
[
	{
		name: "Validation name",
		message: "Error message",
	}
]
array | object | stringArray<ErrorsItem
type ErrorsItem = {
	name?: string; // Name
	message?: string; // Message
};
>
{}Validation errors for this field.
visiblebooleanbooleantrueShow or hide the field.
validatorsarrayArray<unknown>[]Validators attached to this field. Use functions in Vue code, or serializable records such as { name: "minLength", props: { min: 2 } } in generated schemas.
validateOnBlurbooleanbooleantrueRun validators when the field loses focus.
chrome'field' | falsestring'field'Render default field chrome, or false to render only the control while keeping form state wiring.

Auto-generated from Listbox.props and inline _edit hints.

Events

NamePayloadDescription
@update:modelValue(value
value: string;
: string)
Emitted when selection changes.
@select({ option, value })Emitted with the full selected option.
@focus
@blur

Names auto-detected from defineEmits and source emit() calls; payload and description from __doc.events when present.