Skip to content

Select

Presents a selection of choices to the user, activated by a button.

Props


Features

  • 🎹 Keyboard navigation
  • 🍃 Multi-selection mode
  • 🧠 Smart focus management
  • 💬 Highlight items by typing them out (typeahead)

Usage

<script lang="ts">
import { Select } from "melt/builders";
const options = [
"Bleach",
"Dan da Dan",
"Re: Zero",
"Jujutsu Kaisen",
"Attack on Titan",
"Death Note",
] as const;
type Option = (typeof options)[number];
const select = new Select<Option>();
</script>
<label for={select.ids.trigger}>Anime</label>
<button {...select.trigger}>
{select.value ?? "Select an anime"}
</button>
<div {...select.content}>
{#each options as option}
<div {...select.getOption(option)}>
{option}
</div>
{/each}
</div>

Customizing floating elements

Floating elements use Floating UI under the hood. To this end, we expose a floatingConfig option, which can be used to control the underlying computePosition function, its middlewares, and the resulting styling that is applied.

API Reference

Constructor Props

The props that are passed when calling
new Select()
    export type SelectProps<T extends string, Multiple extends boolean = false> = Omit<
    PopoverProps,
    "sameWidth"
    > & {
    /**
    * If `true`, multiple options can be selected at the same time.
    *
    * @default false
    */
    multiple?: MaybeGetter<Multiple | undefined>;
    /**
    * The value for the Select.
    *
    * When passing a getter, it will be used as source of truth,
    * meaning that the value only changes when the getter returns a new value.
    *
    * Otherwise, if passing a static value, it'll serve as the default value.
    *
    *
    * @default false
    */
    value?: MaybeMultiple<T, Multiple>;
    /**
    * Called when the value is supposed to change.
    */
    onValueChange?: OnMultipleChange<T, Multiple>;
    /**
    * The currently highlighted value.
    */
    highlighted?: MaybeGetter<T | null | undefined>;
    /**
    * Called when the highlighted value changes.
    */
    onHighlightChange?: (highlighted: T | null) => void;
    /**
    * How many time (in ms) the typeahead string is held before it is cleared
    * @default 500
    */
    typeaheadTimeout?: MaybeGetter<number | undefined>;
    /**
    * If the content should have the same width as the trigger
    *
    * @default true
    */
    sameWidth?: MaybeGetter<boolean | undefined>;
    /**
    * Determines behavior when scrolling items into view.
    * Set to null to disable auto-scrolling.
    *
    * @default "nearest"
    * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView#block
    */
    scrollAlignment?: MaybeGetter<"nearest" | "center" | null | undefined>;
    };

Methods

The methods returned from
new Select()
  • getOptionId

    (value: T) => string
  • getOption

    (
    value: T,
    options?: { typeahead: string } | undefined,
    ) => {
    readonly "data-melt-select-option": ""
    readonly "data-value": DataReturn<T>
    readonly "data-typeahead": string | undefined
    readonly "aria-hidden": true | undefined
    readonly "aria-selected": boolean
    readonly "data-highlighted": "" | undefined
    readonly role: "option"
    readonly onmouseover: () => void
    readonly onclick: () => void
    }

Properties

The properties returned from
new Select()
  • multiple

    Multiple
  • scrollAlignment

    "nearest" | "center" | null
  • ids

    { trigger: string; content: string; option: string } & {
    invoker: string
    popover: string
    }
  • typeaheadTimeout

    number
  • typeahead

    (letter: string) => { value: T; current: boolean } | undefined
  • isSelected

    (value: T) => boolean
  • select

    (value: T) => void
  • value

    SelectionStateValue<T, Multiple>
  • highlighted

    T | null
  • valueAsString

    string
  • trigger

    {
    readonly onfocus: (event: FocusEvent) => void
    readonly onfocusout: (event: FocusEvent) => Promise<void>
    readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}`
    readonly id: string
    readonly popovertarget: string
    readonly onclick: (e: Event) => void
    } & {
    "data-melt-select-trigger": string
    role: string
    "aria-expanded": boolean
    "aria-controls": string
    "aria-owns": string
    onkeydown: (e: KeyboardEvent) => void
    }
  • content

    {
    readonly onfocus: (event: FocusEvent) => void
    readonly onfocusout: (event: FocusEvent) => Promise<void>
    readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}`
    readonly id: string
    readonly popover: "manual"
    readonly ontoggle: (
    e: ToggleEvent & { currentTarget: EventTarget & HTMLElement },
    ) => void
    readonly tabindex: -1
    readonly inert: boolean
    readonly "data-open": "" | undefined
    } & {
    readonly "data-melt-select-content": ""
    readonly role: "listbox"
    readonly "aria-expanded": boolean
    readonly "aria-activedescendant": string | undefined
    readonly onkeydown: (e: KeyboardEvent) => void
    }