Skip to content
omaris

Inputs

Select

Select — the Input's frame around a styled list of values.

import { Select } from 'omaris'
Learn

Examples

Basic

Give it options and a label; the value is the option's value. For a short, fixed list nobody would search.

<script lang="ts">	import { Select } from 'omaris';​	let city = $state('erbil');​	const CITIES = [		{ value: 'baghdad', label: 'Baghdad' },		{ value: 'erbil', label: 'Erbil' },		{ value: 'basra', label: 'Basra' },		{ value: 'mosul', label: 'Mosul' }	];</script>​<Select class="w-64 max-w-full" label="City" options={CITIES} bind:value={city} />

Descriptions and groups

A description gives each row a second line and group puts rows under a heading — for a plan or a currency, where the name alone does not say enough.

<script lang="ts">	import { Select } from 'omaris';​	let plan = $state('team');​	const PLANS = [		{ value: 'free', label: 'Free', description: 'One project', group: 'Personal' },		{ value: 'pro', label: 'Pro', description: 'Unlimited projects', group: 'Personal' },		{ value: 'team', label: 'Team', description: 'Up to 10 seats', group: 'Business' },		{			value: 'enterprise',			label: 'Enterprise',			description: 'SSO and audit logs',			group: 'Business'		}	];</script>​<Select class="w-72 max-w-full" label="Plan" options={PLANS} bind:value={plan} />

States

The same states a text field has, wired the same way, so a form that mixes selects and text fields validates as one thing.

Choose a size.

<script lang="ts">	import { Select } from 'omaris';​	const SIZES = [		{ value: 's', label: 'Small' },		{ value: 'm', label: 'Medium' },		{ value: 'l', label: 'Large', disabled: true }	];</script>​<Select class="w-52 max-w-full" label="Required" required placeholder="Pick one" options={SIZES} /><Select	class="w-52 max-w-full"	label="Invalid"	invalid	placeholder="Pick one"	supportingText="Choose a size."	options={SIZES}/><Select class="w-52 max-w-full" label="Disabled" disabled value="m" options={SIZES} /><Select class="w-52 max-w-full" label="Clearable" clearable value="s" options={SIZES} />

Native

native renders a real <select>. It gives up the styled list and the descriptions, and gains the platform's own picker — which is what you want on a phone, and in a long form that has to feel native.

<script lang="ts">	import { Select } from 'omaris';​	const YEARS = [		{ value: '2020', label: '2020' },		{ value: '2021', label: '2021' },		{ value: '2022', label: '2022' },		{ value: '2023', label: '2023' },		{ value: '2024', label: '2024' },		{ value: '2025', label: '2025' }	];</script>​<Select class="w-40 max-w-full" label="Styled" options={YEARS} value="2024" /><Select class="w-40 max-w-full" label="Native" native options={YEARS} value="2024" />

Overridden

A Select is a field with the shared popup list under it, so its parts are both sets — field is the closed control, option is a row of the list.

<script lang="ts">	import { Select } from 'omaris';​	const CURRENCIES = [		{ value: 'iqd', label: 'IQD' },		{ value: 'usd', label: 'USD' },		{ value: 'try', label: 'TRY' }	];</script>​<Select	class="w-56 max-w-full"	label="Currency"	options={CURRENCIES}	value="iqd"	classes={{ value: 'font-mono tracking-wide', option: 'font-mono' }}/>

When to use it

Use it for

  • One value from a short, fixed list people already know: a currency, a plan, a region, a status.
  • Rows that need more than a word: description for a second line, icon for a mark that carries into the field, group for headings.
  • A form on a phone, or a long native form. native swaps the styled list for the platform's own picker.

Not for

  • A list you would search rather than scroll (people, products, countries) → Combobox.
  • Two to five choices that can stay visible → Segmented Button; a few choices that each need a line of explanation → Radio.
  • Actions like rename, duplicate, delete → Menu. A Select holds a value; a Menu does something.
  • Several values at once → filter Chips or a column of Checkboxes.
  • On or off → Switch.

Do

  • Give it a placeholder while nothing is chosen, or a value when one is obviously right, like the account's own currency.
  • Add clearable only when "none" is a valid answer, and say so in supportingText.
  • Split a list past a dozen rows with group, so a currency list reads as regions.
  • Use native on a phone form. The styled list is the desktop version.

Don't

  • Use it for yes or no. That is a Switch or two Radios.
  • Hide three options behind a closed field when they fit on the line. A Segmented Button shows them all.
  • Rely on description or icon with native. The OS picker drops both, so the label must stand alone.
  • Pass <option> children and options at once. Children are for the native path only.

Quick reference

variant
  • outline (default)
  • filled
  • ghost
size
  • sm
  • default (default)
  • lg

API

Select

Select — the Input's frame around a styled list of values.

The list is drawn by the library, so it matches the rest of the UI in both themes, shows icons and descriptions, and can be navigated with arrows, Home/End and type-ahead while focus stays on the field. Pass native to get the OS picker instead — the one dropdown that always works on a phone.

For a list you search, use Combobox. For a menu of actions, Menu.

import { Select } from 'omaris'

Parts

Every element this renders is reachable from outside. Pass Tailwind for one part as classes={{ part: '…' }}; class covers the root and is merged last, so it always wins.

root
No description in the source yet.
field
No description in the source yet.
control
The trigger, or the native <select>: keeps its hit area, loses its chrome.
value
No description in the source yet.
chevron
No description in the source yet.
adornment
No description in the source yet.
action
No description in the source yet.
label
No description in the source yet.
support
No description in the source yet.
placeholder
No description in the source yet.
surface
No description in the source yet.
option
No description in the source yet.
group
A non-interactive heading above a run of options.
body
No description in the source yet.
description
No description in the source yet.
check
No description in the source yet.
empty
"No results", "Searching…".
highlight
The part of a label that matched what was typed.

Props

variant

Defaults to 'outline'

SelectVariant
outline
filled
ghost
size

Defaults to 'default'

SelectSize
sm
default
lg
value bindable

Defaults to ''

string

Selected value. Bindable.

options
SelectOption[]

Options to render. Omit and pass <option> children for a native select.

placeholder
string

Shown, greyed, while nothing is chosen.

label
string
required
boolean

Inside a Field, defaults to the field's.

supportingText
string
invalid
boolean

Inside a Field, defaults to the field's.

native

Defaults to false

boolean

Use the OS picker instead of the styled list.

mobileSheet
boolean

On a phone, the list rises from the bottom edge as a sheet — full width, a scrim behind, dragged down to dismiss, rows a thumb can hit — instead of hanging under the field. false keeps it anchored.

clearable

Defaults to false

boolean

Show an × that empties the field.

emptyText

Defaults to 'No options'

string

Text for an empty options array.

start
Snippet

Leading icon inside the frame.

option
Snippet<[SelectOption, { selected: boolean; active: boolean }]>

Custom row rendering for the styled list.

onchange
(value: string, option: SelectOption | undefined) => void
class
string
classes
SelectClasses

Per-part Tailwind overrides. class still covers the root.

children
Snippet
ref bindable

Defaults to null

HTMLSelectElement | HTMLButtonElement | null