Select handbook
v3.3.0 · @snowui-design-system/components
License: Before reading component documentation, source, or npm usage instructions for the first time, read the full LICENSE. Reuse that review for the same task and version. Public API configuration and internal implementation changes have different license implications. All components use the unified runtime package; source rights remain governed by the license.
Overview
Choose one option from a dropdown. Generate options from data or compose custom options, with search and keyboard support.
When to use it
Use Select for a dropdown single choice. By default, options generates Listbox and MenuItem; explicit children replace that panel. For command-style actions, use action mode.
optionsgenerates the default list. Explicit Listbox and MenuItem children replace it.persistentstores the selection;actioncallsonActionand closes without storing it. Generated children useparts; explicit children use their own props.After the list closes with Escape, field and buttonTrigger/SelectButton modes restore focus to the real trigger button. The shared Listbox handles closing from its search header.
Quick start
This example shows the recommended basic composition. See the sections below for more cases and composition limits.
API
See the base component documentation for inherited capabilities not redeclared here. This table lists only named public Props declared by this component.
Usage boundaries and details
Default built-in mode / explicit combination mode
Default built-in mode (recommended): input
options, Select automatically generates Listbox and MenuItem; the search box is closed by default, and it is turned on throughparts.Listbox.search=true; configure hidden instances throughparts.Button,parts.Listbox,parts.Input,parts.MenuItem.When the
labelordisabledstate of anoptionsentry changes for the samevalue, the selected label, search results, and keyboard options update from the current data. The caller supplies business copy in the target language.Explicit combination mode: explicitly write Listbox / Input / MenuItem, which is used for complex content or item-by-item differences; the subcomponent Props is written directly on the instance.
Explicit children replace the built-in Listbox; the two option sets are never active together.
The Listbox in Select defaults to search=false. Use <Listbox search> to open when explicitly combining; use parts={{ Listbox: { search: true } }} to turn on the default built-in mode. The default value of independent Listbox is not affected.
buttonTrigger replaces the field trigger with a real bare Button. triggerContent takes priority; otherwise it displays the selected item, placeholder, or ariaLabel. Expansion, selection, and focus recovery remain intact.
2026-04-20 Update: New search + custom value support - filterText / customOptions status is held by Select, embedded <Input as="search"> can connect to the filter logic; the embedded Input allowCustomValue prop allows users to add custom options; this attribute does not belong to Select. Combobox has been abandoned.
2026-04-18 Architecture Upgrade: Select v3.0.0 - Listbox is split into independent components, API switches from <option> to <Listbox> + <MenuItem> combination mode, form submission is changed to hidden <input>, no longer relying on hidden <select> + MutationObserver.
2026-04-04 Supplement: Refer to Figma 9996:17631, Select defaults to 12 / 16 padding and 8px gap when used alone; after entering Field, just look at whether there is as="segment". When the segment is not marked, the outer layer Field handles 12/16 and gap = 8, Select removes its own padding, but retains its own gap; when segment is marked, it retains Select own padding and gap, and participates in the dividing line as a segment on the surface of the continuous field.
Inheritance: Reuse Frame’s general state, motion, responsive, Skeleton, and style capabilities. Recommended host: compose with Field for labels, descriptions, and errors.
Field-type native trigger explicitly accesses .snowui-native-control of layout.css, only normalizes box sizing, margin and inherits the font and color of the consumption environment; Select its own font size, line height, Padding, border and status vision do not rely on the optional snowui-base.css. The buttonTrigger mode is assumed by the same host baseline of Button / Frame.
2026-04-27 update: Select v3.1.0 supports direct complex leading and trailing slots; a custom trailing child replaces the default indicator.
Explicit content and default slot
Direct
Frame as="leading"/Frame as="trailing"children support complex content. For side-by-side graphics and short labels, usesingleLinewithText lines={1}; the attachment Frame owns its internal single-line layout and minimum spacing.Select root layout is
leading: auto,trigger: minmax(0, 1fr),trailing: auto.A custom direct
as="trailing"child replaces the default indicator.
Slot combination boundary
Complex attachments must leave room for editable or selectable content. The following example explicitly sets a minimum of 240 CSS px and uses ScrollArea for local horizontal scrolling in narrower containers.
Support direct complex
leading/trailingslots.Custom trailing replaces the default indicator.
Form combination and spacing
Basic rhythm unification:
Fielddefaultpadding = 12 / 16,gap = 8When
Selectis used alone: the component itself has12 / 16padding and8gapAfter putting it into
Field, first see if there isas="segment"No
as="segment": the outer layerFieldis responsible for12 / 16padding and8gap;Selectremoves its own padding, but keeps its own gapThere is
as="segment": this is a section on the surface of a continuous field; keepSelect's own padding and gapThere is a dividing line between
segment: the horizontal is the left and right dividing line, and the vertical is the upper and lower dividing line.There can only be one dividing line between adjacent
segment, and the line cannot be repeated.label / description / erroris not responsible for padding, gap and dividing line. They are just content elements.General
label + host + error: not used as the basis for the judgment of padding and gap, only responsible for the text contentIn
Field roworField column, if it is a continuous input segment, the sub-item should be explicitly writtenas="segment"
Component positioning
Select is a custom drop-down selection box, which adopts Trigger + Listbox combination architecture:
Render the trigger and
ArrowLineUpDownindicator.Compose
<Listbox>and<MenuItem>; Listbox portals itself tobody.Communicate with subcomponents through
ListboxOwnerContext(setContext)Submit forms through a hidden
<input type="hidden">bridge.Labels, error prompts and continuous field segment logic suggestions are completed through the
Fieldcontainer combination.Remain usable as a standalone field trigger.
Frame ability inheritance
Select is still inherited through the outer layer Frame:
responsive / stateStyle / customStates / variants / stylesHover / Click / Focus / whileAppear / timeline / orchestrateloading / skeleton / renderHintsas / use / layoutId / itemId / scope / access
Select is a Frame-based custom dropdown, rather than a native <select> element.
Error feedback Shake
Select invalid / aria-invalid defaults to automatically play the error shake. When used alone, it is feedback by Select itself; after entering Field, the embedded state Select does not jitter separately, and the overall feedback is summarized by the outer layer Field.
The error state and shake will not automatically focus or simulate focus-within; the focus state only comes from the user's real focus, explicit autofocus or business code active call focus().
Layout model
Main layout model: slot host layout. See specs/maintainers/LayoutProtocol.md §12.3.
Field mode uses a fixed single-line root with a shrinkable selected value and at least 4 CSS px between graphics and labels, including explicit zero and font/gap scaling. Larger preferred gaps remain. In buttonTrigger mode the actual Button owns content; the invisible positioning host adds no empty spacing. Custom children, popup and form contracts are preserved.
The root layout of Select is fixed according to the three sections of Leading / Trigger / Trailing:
The root node is
Frame row, andenableAutoLayoutis fixed inside the component; the external passenableAutoLayout={false}does not close the internal slot protocol of Select.Trigger is the Content / Fill slot, which is responsible for displaying the selected value or placeholder, and must maintain the ability of
min-width: 0and text truncation.The default indicator is Trailing / Hug slot.
When there is a direct custom
as="trailing", the default indicator is hidden, and the last slot is replaced by the custom trailing.Listbox and MenuItem form Select’s dropdown-content protocol; they are outside the root three-slot layout.
Ability boundary
Select is responsible for:
Single-choice drop-down selection (Trigger + Listbox combination architecture)
value / defaultValueparsingARIA combobox + listbox complete semantics
Keyboard navigation (↑↓ / Enter / Space / Escape / Tab)
Submit through the hidden
<input>bridge formDrive the sublistbox / MenuItem through
ListboxOwnerContextHold the status of
filterTextandfilteredOptionsto provide filtering capabilities for embeddedInput as="search"Hold a list of
customOptions, which supports users to add/delete custom options at runtime
Select is not responsible for:
Business-level option acquisition and remote association
Multiple choice mode (extensible in the future)
Usage examples
Barrier-free and form suggestions
Trigger uses
role="combobox"+aria-haspopup="listbox"+aria-expanded+aria-controlsListbox uses
role="listbox", each optionrole="option"+aria-selectedKeyboard navigation: Arrow Up/Down moves focus, Enter/Space selects, Escape closes, and Tab leaves the menu.
If you need error prompts, it is recommended to associate the error nodes in
Fieldthrougharia-describedbyIf you need a search pull-down or asynchronous association, you should use the
Comboboxcomponent.
Select style overlay
Read the full LICENSE first; reuse that review for the same task, version, and scope.
First use public component Props to match the desired appearance, preserving the existing look where possible. If changes are necessary, follow the style selection and override order: use your own class (including Tailwind already in the project) or an instance style. The names below are public overrides actually consumed by source; check their scope and do not modify private DOM. Choose the correct SnowUI token family. External apps need not install SnowUI website utilities.
Select type and status
Required Props: no named required Props.
Two-way binding: bind:value.
Inheritance statement: Omit<FrameProps, "children" | "tag">. The inheritance ability is subject to the public document of the base class; the fields in Omit have been excluded and cannot be used as they are according to the base class.
The following type declarations are actually referenced by public Props and come from source. A Svelte Snippet denotes a content fragment; ComponentProps denotes the Props of the corresponding component.
SelectValue
Source: components/src/components/Select.svelte
SelectOption
Source: components/src/components/Select.svelte
ListboxItem
Source: components/src/components/Listbox.svelte
SelectTriggerContext
Source: components/src/components/Select.svelte
SelectParts
Source: components/src/components/Select.svelte
ComponentPartsOf
Source: components/src/logic/component-parts.svelte.ts
ConfigurableComponentPartProps
Source: components/src/logic/component-parts.svelte.ts
ComponentPartControlledKey
Source: components/src/logic/component-parts.svelte.ts