Inputs

Select

A dropdown for choosing one or more options from a short list.

Installation

pnpm dlx @mielui/svelte add select

Usage

Single selection is the default and binds a string. Select.Value shows the selected label, or its placeholder while nothing is chosen; Trigger renders it when you pass no children. Bind value or use onValueChange on Root to react to both pointer and keyboard selection; an item onclick handler only sees native clicks.

<script lang="ts">
    import * as Select from '@mielui/svelte/components/select';

    let role = $state('');
</script>

<Select.Root bind:value={role}>
    <Select.Trigger aria-label="Role">
        <Select.Value placeholder="Select a role" />
    </Select.Trigger>
    <Select.Content>
        <Select.Item value="designer">Designer</Select.Item>
        <Select.Item value="engineer">Engineer</Select.Item>
    </Select.Content>
</Select.Root>

Set type="multiple" to bind a string array; selecting an item toggles it without closing the menu, and Select.Value joins the selected labels. Use name to include the selection in a form; multiple values share the field name and can be read with FormData.getAll(). Root also accepts disabled and required.

Arrow keys, Home, End, and typing move between options; disabled items are skipped. Before an option has mounted, a preselected value shows as its value string.

Examples

Multiple selection

Select several teams, clear the selection, or submit the named values. Disabled options stay unavailable.

Scrollable

A max-h-* class on Content caps the menu height; long lists scroll inside it.

Dynamic width

With dynamic on Content, the menu sizes to its longest option, even when the trigger is narrower.

Glass surface

surface="glass" on Content gives the menu a translucent, blurred background. Omit surface to inherit --mielui-surface from your theme, or set surface="solid" to override it. Glass keeps an opaque fallback when backdrop filtering is unavailable and respects reduced-transparency preferences.

Controlled open state

Bind open on Root to open or close the list from your own code. onOpenChange reports when the person opens or closes it.

Trigger and items

Trigger needs a name. Pass aria-label, or point aria-labelledby at the id of a visible label so the label and the chosen value are read together. Trigger is a Button with a chevron: it takes variant, size, and bind:element, and unstyled removes the Button classes so class alone styles it. onopen runs just before the list opens. Its onclick runs first; call preventDefault() there to keep the list closed.

Item is a Button too, but it always uses the menu row style, so Button's variant, size, and unstyled do not apply. Pass label when the trigger should show different text than the option content. loading with labels shows progress on an option that starts slow work. An option is always a button and does not take href.

Content, Label, Item and Trigger accept class. Use Select.Label to head a group of options inside Content.

API reference

Select.Root

Provides select state.

  • open Bindable
    boolean

    Whether it is open. Bind it to control the state from outside.

    Default false

  • onOpenChange
    ((open: boolean) => void)

    Called with the new state whenever it opens or closes.

  • name
    string

    Field name submitted with the form.

  • disabled
    boolean

    Prevents interaction and dims the control.

    Default false

  • required
    boolean

    Requires a value before the form can be submitted.

    Default false

  • children
    Snippet<[]>

    Content rendered inside.

  • type
    "single" | "multiple"

    single keeps one value. multiple allows several and makes value an array.

    Default 'single'

  • value Bindable
    string | string[]

    Selected value, or an array in multiple mode. Bindable.

    Default type === 'multiple' ? [] : ''

  • onValueChange
    ((value: string) => void) | ((value: string[]) => void)

    Called with the new value when it changes.

Select.Content

Renders select options.

  • surface
    "solid" | "glass"

    Surface treatment. Omit it to inherit --mielui-surface from the theme.

  • dynamic
    boolean

    Sizes the list to its longest option, even when the trigger is narrower.

    Default false

  • class
    string

    Classes added to the element.

  • children Required
    Snippet<[]>

    Content rendered inside.

Select.Item

Defines a selectable option.

  • value Required
    string | (string & string[])

    Value this option selects.

  • label
    string

    Text shown in the trigger when it differs from the option's content.

  • children
    Snippet<[]>

    Content rendered inside.

  • onkeydown
    ((event: KeyboardEvent) => void)

    Called on key down, before the button handles the key itself.

  • onclick
    ((event: MouseEvent) => void)

    Called when the button is activated. Loading and disabled buttons do not call it.

  • status
    ButtonStatus

    Controlled visual state. Loading remains focusable and refuses activation.

  • disabled
    boolean

    Prevents activation. A disabled link loses its destination and is skipped by Tab.

  • element Bindable
    HTMLButtonElement | HTMLAnchorElement

    Bindable reference to the rendered DOM element. Type is the union of the two possible element types -- narrow at the use site:

  • loading
    boolean

    Convenience alias for status="loading".

  • labels
    ButtonLabels

    Overrides the built-in text and accessible names. Every key is optional and English is the fallback.

Select.Label

Labels a select section.

  • class
    string

    Classes added to the element.

  • children Required
    Snippet<[]>

    Content rendered inside.

Select.Trigger

Opens the select menu.

  • children
    Snippet<[]>

    Content rendered inside. Defaults to Select.Value.

  • class
    string

    Classes added to the element.

  • variant
    ButtonVariant

    Button style of the trigger.

    Default 'outline'

  • aria-labelledby
    string

    Id of the element that labels the trigger.

  • aria-invalid
    Booleanish | "grammar" | "spelling" | null

    Marks the trigger as invalid for assistive technology and error styling.

  • style
    string

    Inline styles for the element.

  • onclick
    ((event: MouseEvent) => void)

    Called when it is clicked or activated.

  • size
    "sm" | "md" | "lg" | "icon"

    Control height of the trigger.

  • element Bindable
    HTMLButtonElement | HTMLAnchorElement

    Bindable reference to the DOM element.

  • unstyled
    boolean

    Forwarded to Button: render with class alone, skipping variant/size.

  • onopen
    (() => void)

    Called immediately before this trigger opens its popover.

Select.Value

Displays the selected value.

  • placeholder
    string

    Text shown while nothing is selected.

    Default 'Select'

  • class
    string

    Classes added to the element.