Select
Displays a list of options for the user to pick from, triggered by a button.
Quick Start
<%= kui(:select, name: :fruit) do %>
<%= kui(:select, :trigger) do %>
<%= kui(:select, :value, placeholder: "Select a fruit") %>
<% end %>
<%= kui(:select, :content) do %>
<%= kui(:select, :group) do %>
<%= kui(:select, :label) { "Fruits" } %>
<%= kui(:select, :item, value: "apple") { "Apple" } %>
<%= kui(:select, :item, value: "banana") { "Banana" } %>
<%= kui(:select, :item, value: "blueberry") { "Blueberry" } %>
<% end %>
<% end %>
<% end %>
Locals
Select (root)
| Local | Type | Default |
|---|---|---|
name: |
Symbol | String |
nil |
css_classes: |
String |
"" |
**component_options |
Hash |
{} |
SelectTrigger
| Local | Type | Default |
|---|---|---|
size: |
:sm | :md |
:md |
disabled: |
Boolean |
false |
css_classes: |
String |
"" |
**component_options |
Hash |
{} |
SelectValue
| Local | Type | Default |
|---|---|---|
placeholder: |
String |
nil |
css_classes: |
String |
"" |
**component_options |
Hash |
{} |
SelectItem
| Local | Type | Default |
|---|---|---|
value: |
String |
(required) |
disabled: |
Boolean |
false |
css_classes: |
String |
"" |
**component_options |
Hash |
{} |
Sub-parts
| Part | Usage | Purpose |
|---|---|---|
:trigger |
kui(:select, :trigger) |
Button that opens the dropdown |
:value |
kui(:select, :value) |
Displays current selection or placeholder |
:content |
kui(:select, :content) |
Dropdown panel (listbox) |
:group |
kui(:select, :group) |
Groups related items |
:label |
kui(:select, :label) |
Group heading label |
:item |
kui(:select, :item) |
Selectable option with checkmark indicator |
:separator |
kui(:select, :separator) |
Divider between groups |
All sub-parts accept css_classes: and **component_options.
Anatomy
Select
├── SelectTrigger
│ ├── SelectValue
│ └── ChevronDown icon
├── SelectContent (listbox)
│ ├── SelectGroup
│ │ ├── SelectLabel
│ │ ├── SelectItem
│ │ │ ├── Checkmark indicator
│ │ │ └── Item text
│ │ └── ...
│ ├── SelectSeparator
│ └── SelectGroup
│ └── ...
└── Hidden input (form submission)
Usage
Groups with Labels
Use SelectGroup, SelectLabel, and SelectSeparator to organize items.
<%= kui(:select, name: :food) do %>
<%= kui(:select, :trigger) do %>
<%= kui(:select, :value, placeholder: "Select a fruit") %>
<% end %>
<%= kui(:select, :content) do %>
<%= kui(:select, :group) do %>
<%= kui(:select, :label) { "Fruits" } %>
<%= kui(:select, :item, value: "apple") { "Apple" } %>
<%= kui(:select, :item, value: "banana") { "Banana" } %>
<% end %>
<%= kui(:select, :separator) %>
<%= kui(:select, :group) do %>
<%= kui(:select, :label) { "Vegetables" } %>
<%= kui(:select, :item, value: "carrot") { "Carrot" } %>
<%= kui(:select, :item, value: "broccoli") { "Broccoli" } %>
<% end %>
<% end %>
<% end %>
Disabled
Disable the entire select or individual items.
<%= kui(:select, :trigger, disabled: true) do %>
<%= kui(:select, :value, placeholder: "Select a fruit") %>
<% end %>
<%= kui(:select, :item, value: "grapes", disabled: true) { "Grapes" } %>
With Field
Wrap in a Field for label, description, and error support.
<%= kui(:field) do %>
<%= kui(:field, :label, for: :fruit) { "Fruit" } %>
<%= kui(:select, name: :fruit) do %>
<%= kui(:select, :trigger) do %>
<%= kui(:select, :value, placeholder: "Select a fruit") %>
<% end %>
<%= kui(:select, :content) do %>
<%= kui(:select, :group) do %>
<%= kui(:select, :item, value: "apple") { "Apple" } %>
<%= kui(:select, :item, value: "banana") { "Banana" } %>
<% end %>
<% end %>
<% end %>
<%= kui(:field, :description) { "Choose your favorite fruit." } %>
<% end %>
Validation
Set aria-invalid on the trigger and invalid: true on the Field.
<%= kui(:field, invalid: true) do %>
<%= kui(:field, :label, for: :language) { "Language" } %>
<%= kui(:select, name: :language) do %>
<%= kui(:select, :trigger, "aria-invalid": true) do %>
<%= kui(:select, :value, placeholder: "Select a language") %>
<% end %>
<%= kui(:select, :content) do %>
<%= kui(:select, :group) do %>
<%= kui(:select, :item, value: "ruby") { "Ruby" } %>
<%= kui(:select, :item, value: "python") { "Python" } %>
<% end %>
<% end %>
<% end %>
<%= kui(:field, :error, errors: ["Please select a language."]) %>
<% end %>
Size
The trigger supports sm and md sizes.
<%= kui(:select, :trigger, size: :sm) do %>...<% end %>
<%= kui(:select, :trigger, size: :md) do %>...<% end %>
Theme
# lib/kiso/themes/select.rb
SelectTrigger = ClassVariants.build(
base: "text-foreground flex w-full items-center justify-between gap-2
rounded-md bg-background px-3 py-2 text-sm whitespace-nowrap shadow-xs
ring ring-inset ring-accented outline-none transition-[color,box-shadow]
focus-visible:ring-2 focus-visible:ring-primary
aria-invalid:ring-error aria-invalid:focus-visible:ring-error
disabled:cursor-not-allowed disabled:opacity-50",
variants: { size: { sm: "h-8", md: "h-9" } },
defaults: { size: :md }
)
SelectContent = ClassVariants.build(
base: "bg-background text-foreground z-50 max-h-60 min-w-32
overflow-y-auto rounded-md shadow-md ring ring-inset ring-border p-1"
)
SelectItem = ClassVariants.build(
base: "relative flex w-full cursor-default items-center gap-2 rounded-sm
py-1.5 pr-8 pl-2 text-sm outline-none select-none
data-[highlighted]:bg-elevated data-[highlighted]:text-foreground"
)
SelectLabel = ClassVariants.build(base: "text-muted-foreground px-2 py-1.5 text-xs font-medium")
SelectSeparator = ClassVariants.build(base: "bg-border pointer-events-none -mx-1 my-1 h-px")
Stimulus Controller
The Select component requires the kiso--select Stimulus controller for
interactivity. It handles:
- Toggle open/close on trigger click
- Close on outside click and Escape key
- Keyboard navigation (Arrow keys, Home, End)
- Enter/Space to select highlighted item
- Type-ahead character matching
- Hidden input sync for form submission
- Checkmark indicator on selected item
Register the controller in your application:
import KisoUi from "kiso-ui"
KisoUi.start(application)
Accessibility
| Attribute | Value |
|---|---|
role="listbox" |
On the content panel |
role="option" |
On each item |
aria-haspopup="listbox" |
On the trigger |
aria-expanded |
true/false on trigger |
aria-selected |
true on selected item |
aria-invalid |
Set when validation fails |
aria-disabled |
On disabled items |
data-slot |
"select", "select-trigger", etc. |
Keyboard
| Key | Action |
|---|---|
Space / Enter |
Open select or select highlighted item |
ArrowDown / ArrowUp |
Navigate through items |
Home / End |
Jump to first / last item |
Escape |
Close the dropdown |
Tab |
Close and move focus |
| Character key | Type-ahead to matching item |