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
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
modelValue | string | number | string | '' | Selected option value. |
options* | array | Array< | — | Available options. |
orientation | 'vertical' | 'horizontal' | string | 'vertical' | Arrow key direction. |
Field props
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
id | string | string | '' | Optional ID override. By default parent forms derive the input ID from the field path using underscores. |
name | string | string | '' | Local field name. Parent forms derive the full field path and native HTML name from the form hierarchy. |
label | string | string | '' | Visible field label. |
description | string | string | '' | Optional helper copy below the field. |
placeholder | string | string | '' | Placeholder shown when the control is empty. |
required | boolean | boolean | false | Mark the field as required. |
disabled | boolean | boolean | false | Disable field interaction. |
readOnly | boolean | boolean | false | Show the value but prevent editing. |
invalid | boolean | boolean | false | Mark the field invalid. |
errors | array | object | string | Array< | {} | Validation errors for this field. |
visible | boolean | boolean | true | Show or hide the field. |
validators | array | Array<unknown> | [] | Validators attached to this field. Use functions in Vue code, or serializable records such as { name: "minLength", props: { min: 2 } } in generated schemas. |
validateOnBlur | boolean | boolean | true | Run validators when the field loses focus. |
chrome | 'field' | false | string | '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
| Name | Payload | Description |
|---|---|---|
| @update:modelValue | ( | 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.