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>
<script lang="ts"> import { Select } from "melt/components";
const options = [ "Bleach", "Dan da Dan", "Re: Zero", "Jujutsu Kaisen", "Attack on Titan", "Death Note", ] as const; type Option = (typeof options)[number];</script>
<Select> {#snippet children(select)} <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> {/snippet}</Select>
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()
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>;};
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()
new Select()
-
getOptionId
(value: T) => string(value: T) => string -
getOption
(value: T,options?: { typeahead: string } | undefined,) => {readonly "data-melt-select-option": ""readonly "data-value": DataReturn<T>readonly "data-typeahead": string | undefinedreadonly "aria-hidden": true | undefinedreadonly "aria-selected": booleanreadonly "data-highlighted": "" | undefinedreadonly role: "option"readonly onmouseover: () => voidreadonly onclick: () => void}(value: T,options?: { typeahead: string } | undefined,) => {readonly "data-melt-select-option": ""readonly "data-value": DataReturn<T>readonly "data-typeahead": string | undefinedreadonly "aria-hidden": true | undefinedreadonly "aria-selected": booleanreadonly "data-highlighted": "" | undefinedreadonly role: "option"readonly onmouseover: () => voidreadonly onclick: () => void}
Properties
The properties returned from
new Select()
new Select()
-
multiple
MultipleMultiple -
scrollAlignment
"nearest" | "center" | null"nearest" | "center" | null -
ids
{ trigger: string; content: string; option: string } & {invoker: stringpopover: string}{ trigger: string; content: string; option: string } & {invoker: stringpopover: string} -
typeaheadTimeout
numbernumber -
typeahead
(letter: string) => { value: T; current: boolean } | undefined(letter: string) => { value: T; current: boolean } | undefined -
isSelected
(value: T) => boolean(value: T) => boolean -
select
(value: T) => void(value: T) => void -
value
SelectionStateValue<T, Multiple>SelectionStateValue<T, Multiple> -
highlighted
T | nullT | null -
valueAsString
stringstring -
trigger
{readonly onfocus: (event: FocusEvent) => voidreadonly 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: stringreadonly popovertarget: stringreadonly onclick: (e: Event) => void} & {"data-melt-select-trigger": stringrole: string"aria-expanded": boolean"aria-controls": string"aria-owns": stringonkeydown: (e: KeyboardEvent) => void}{readonly onfocus: (event: FocusEvent) => voidreadonly 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: stringreadonly popovertarget: stringreadonly onclick: (e: Event) => void} & {"data-melt-select-trigger": stringrole: string"aria-expanded": boolean"aria-controls": string"aria-owns": stringonkeydown: (e: KeyboardEvent) => void} -
content
{readonly onfocus: (event: FocusEvent) => voidreadonly 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: stringreadonly popover: "manual"readonly ontoggle: (e: ToggleEvent & { currentTarget: EventTarget & HTMLElement },) => voidreadonly tabindex: -1readonly inert: booleanreadonly "data-open": "" | undefined} & {readonly "data-melt-select-content": ""readonly role: "listbox"readonly "aria-expanded": booleanreadonly "aria-activedescendant": string | undefinedreadonly onkeydown: (e: KeyboardEvent) => void}{readonly onfocus: (event: FocusEvent) => voidreadonly 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: stringreadonly popover: "manual"readonly ontoggle: (e: ToggleEvent & { currentTarget: EventTarget & HTMLElement },) => voidreadonly tabindex: -1readonly inert: booleanreadonly "data-open": "" | undefined} & {readonly "data-melt-select-content": ""readonly role: "listbox"readonly "aria-expanded": booleanreadonly "aria-activedescendant": string | undefinedreadonly onkeydown: (e: KeyboardEvent) => void}