Select
A dropdown selection control with typeahead search, grouped options, and custom placement.
import { Select, SelectItem } from "@glint/components/select.slint";import { Tokens } from "@glint/theme/tokens.slint";
export component Demo inherits Window { width: 560px; height: 320px; background: Tokens.color-background;
in-out property <int> plan-index: 1;
VerticalLayout { alignment: center; spacing: 16px; padding: 24px;
HorizontalLayout { alignment: center;
Select { accessible-label: "Select Subscription Plan"; placeholder: "Choose a plan…"; selected-index <=> root.plan-index; items: [ { value: "free", label: "Free Plan ($0/mo)" }, { value: "pro", label: "Pro Plan ($20/mo)" }, { value: "team", label: "Team Plan ($50/mo)" }, { value: "enterprise", label: "Enterprise Plan", disabled: true }, ]; } }
Text { text: "Selected plan index: " + root.plan-index; color: Tokens.color-muted-foreground; font-size: Tokens.typography-body-sm-size; horizontal-alignment: center; } }}Usage
import { Select, SelectItem } from "@glint/components/select.slint";
export component AppWindow inherits Window { in-out property <int> fruit-index: -1;
VerticalLayout { alignment: center;
Select { placeholder: "Pick a fruit…"; selected-index <=> root.fruit-index; items: [ { value: "apple", label: "Apple" }, { value: "banana", label: "Banana" }, { value: "cherry", label: "Cherry" }, ]; changed(index) => { // handle pick } } }}Select displays a button trigger that opens a floating options list built on Glint’s Panel overlay primitive.
Selecting an option sets selected-index and fires changed(index).
Keyboard users can navigate with ↑/↓, jump to list boundaries with Home/End, and type alphanumeric characters for instant prefix matching via type-to-select.
Examples
Placement strategies
placement controls where the dropdown popup opens relative to the trigger.
SelectPlacement.below places the popup’s top edge below the trigger.
SelectPlacement.selected-item lifts the popup so that the currently selected item aligns directly over the trigger, mimicking desktop native select controls.
import { Select, SelectPlacement } from "@glint/components/select.slint";import { Tokens } from "@glint/theme/tokens.slint";
export component Demo inherits Window { width: 560px; height: 320px; background: Tokens.color-background;
in-out property <int> item-idx: 2;
VerticalLayout { alignment: center; spacing: 16px; padding: 24px;
HorizontalLayout { alignment: center;
Select { placement: SelectPlacement.selected-item; selected-index <=> root.item-idx; items: [ { value: "us", label: "United States (UTC-5)" }, { value: "eu", label: "European Union (UTC+1)" }, { value: "br", label: "Brazil (UTC-3)" }, { value: "jp", label: "Japan (UTC+9)" }, ]; } }
Text { text: "Placement: SelectPlacement.selected-item"; color: Tokens.color-muted-foreground; font-size: Tokens.typography-body-sm-size; horizontal-alignment: center; } }}Grouped rows
Glint components that render lists (Select, Combobox, Command, MenuPanel) share a unified grouped-row model.
Groups are not separate items in the data array; they ride on the first item of each group:
separator-before: truedraws a hairline divider above that row.heading-before: "..."displays a non-selectable category title above that row.
This architecture preserves exact 1-to-1 array indexing (0, 1, 2…) for actionable options and ensures screen readers do not count headers as selectable choices.
import { Select } from "@glint/components/select.slint";import { Tokens } from "@glint/theme/tokens.slint";
export component Demo inherits Window { width: 560px; height: 320px; background: Tokens.color-background;
VerticalLayout { alignment: center; padding: 24px;
HorizontalLayout { alignment: center;
Select { placeholder: "Select food…"; items: [ { value: "apple", label: "Apple", heading-before: "Fruits" }, { value: "banana", label: "Banana" }, { value: "orange", label: "Orange" }, { value: "carrot", label: "Carrot", separator-before: true, heading-before: "Vegetables" }, { value: "broccoli", label: "Broccoli" }, { value: "spinach", label: "Spinach" }, ]; } } }}Disabled options and validation error state
Set disabled: true on a SelectItem to prevent its selection while keeping its place in the list.
Set invalid: true on the Select component to display a destructive error border and announce an invalid state.
import { Select } from "@glint/components/select.slint";import { Tokens } from "@glint/theme/tokens.slint";
export component Demo inherits Window { width: 560px; height: 320px; background: Tokens.color-background;
VerticalLayout { alignment: center; spacing: 16px; padding: 24px;
HorizontalLayout { alignment: center;
Select { invalid: true; placeholder: "Required selection…"; items: [ { value: "active", label: "Active Project" }, { value: "archived", label: "Archived Project (Disabled)", disabled: true }, { value: "draft", label: "Draft Project" }, ]; } }
Text { text: "Select invalid: true"; color: Tokens.color-destructive; font-size: Tokens.typography-body-sm-size; horizontal-alignment: center; } }}Type-to-select and search labels
Typeahead search matches keystrokes against option labels. When dealing with accents or diacritics, provide an unaccented search-label so readers can type standard ASCII keys to match localized names.
import { Select } from "@glint/components/select.slint";import { Tokens } from "@glint/theme/tokens.slint";
export component Demo inherits Window { width: 560px; height: 320px; background: Tokens.color-background;
VerticalLayout { alignment: center; padding: 24px;
HorizontalLayout { alignment: center;
Select { placeholder: "Choose a city…"; items: [ { value: "sp", label: "São Paulo", search-label: "sao paulo" }, { value: "mch", label: "München", search-label: "munchen" }, { value: "tyo", label: "Tokyo", search-label: "tokyo" }, { value: "prs", label: "Paris", search-label: "paris" }, ]; } } }}API Reference
Properties
| Property | Type | Default | Description |
|---|---|---|---|
items | in [SelectItem] | no default | Options shown in the dropdown. |
selected-index | in-out int | -1 | Two-way; index of the chosen item, or -1 for no selection. |
placeholder | in string | @tr("Select…") | Shown when nothing is selected. |
disabled | in bool | false | When true, the trigger dims and stops opening. |
invalid | in bool | false | When true, the trigger wears the destructive border and the control announces itself invalid. The message that explains the error belongs to the surrounding Field — bind this to that Field's invalid. |
placement | in SelectPlacement | SelectPlacement.below | Where the dropdown opens — edge-aligned below the trigger, or lifted so the selected row lands over it. |
highlighted-index | in-out int | 0 | Internal — which item is highlighted by arrow keys inside the popup. |
is-open | out bool | no default | True while the dropdown popup is on screen; mirrors popup.is-open. |
focus-visible | out bool | no default | Whether this control holds the keyboard *and* got it from the keyboard — the focus-visible a hover surface opens on. Published because Slint reports focus only to the element holding it, so a Tooltip wrapping this control cannot read it off the scope inside (tooltip.slint). |
focus-held | out bool | no default | The same focus, still true while a popup has borrowed the window's — what a hover surface opened by this control has to gate on, since showing itself is what takes focus-visible away. See Tooltip. |
Callbacks
| Callback | Description |
|---|---|
changed(int) | Fired with the new selected-index when the user picks an item. |
Functions
| Function | Description |
|---|---|
focus-from-keyboard() | Hand the control the keyboard the way a key press does, ring and all. A host that moves the focus onto a control because the user pressed something — Questionnaire stepping to the next question — cannot use focus(): Slint reports that as programmatic, which is how a host parking the keyboard looks, and the scope drops the ring for it. Published by every control that publishes focus-visible, for the same reason: the scope inside cannot be reached from outside the component. |
Enums
| Enum | Values |
|---|---|
SelectPlacement | below, selected-item |
Accessibility
- Combobox role. The trigger element acts as an accessible
comboboxnode carryingaccessible-expandable,accessible-expanded, and the currently selected value. - List semantics. The dropdown popup is exposed as a
listwhere each option is alist-itemcarrying its index and selection state. - Group headings. Headings and separator lines are non-interactive structural elements and never receive keyboard focus.
- Disabled options. Disabled options are reported as unavailable to screen readers and skipped by arrow keys and type-to-select matching.
- Keyboard navigation. Enter, Space, or ↓ on the trigger opens the dropdown. ↑/↓ navigate items, and alphanumeric typing highlights matching items. Enter commits the selection and Escape dismisses without changes.