Select
Displays a list of options for the user to pick from, triggered by a button.
Examples
Basic Select
A simple select with a few options.
<%= render "ui/select" do %>
<%= render "ui/select/trigger", placeholder: "Select a fruit..." %>
<%= render "ui/select/content" do %>
<%= render "ui/select/item", value: "apple" do %>Apple<% end %>
<%= render "ui/select/item", value: "banana" do %>Banana<% end %>
<%= render "ui/select/item", value: "orange" do %>Orange<% end %>
<% end %>
<% end %><%= render UI::Select.new do %>
<%= render UI::SelectTrigger.new(placeholder: "Select a fruit...") %>
<%= render UI::SelectContent.new do %>
<%= render UI::SelectItem.new(value: "apple") { "Apple" } %>
<%= render UI::SelectItem.new(value: "banana") { "Banana" } %>
<%= render UI::SelectItem.new(value: "orange") { "Orange" } %>
<% end %>
<% end %><%= render UI::SelectComponent.new do %>
<%= render UI::SelectTriggerComponent.new(placeholder: "Select a fruit...") %>
<%= render UI::SelectContentComponent.new do %>
<%= render(UI::SelectItemComponent.new(value: "apple")) { "Apple" } %>
<%= render(UI::SelectItemComponent.new(value: "banana")) { "Banana" } %>
<%= render(UI::SelectItemComponent.new(value: "orange")) { "Orange" } %>
<% end %>
<% end %>With Default Value
Select with a pre-selected value.
<%= render "ui/select", value: "banana" do %>
<%= render "ui/select/trigger", placeholder: "Select a fruit..." %>
<%= render "ui/select/content" do %>
<%= render "ui/select/item", value: "apple" do %>Apple<% end %>
<%= render "ui/select/item", value: "banana" do %>Banana<% end %>
<%= render "ui/select/item", value: "orange" do %>Orange<% end %>
<% end %>
<% end %><%= render UI::Select.new(value: "banana") do %>
<%= render UI::SelectTrigger.new(placeholder: "Select a fruit...") %>
<%= render UI::SelectContent.new do %>
<%= render UI::SelectItem.new(value: "apple") { "Apple" } %>
<%= render UI::SelectItem.new(value: "banana") { "Banana" } %>
<%= render UI::SelectItem.new(value: "orange") { "Orange" } %>
<% end %>
<% end %><%= render UI::SelectComponent.new(value: "banana") do %>
<%= render UI::SelectTriggerComponent.new(placeholder: "Select a fruit...") %>
<%= render UI::SelectContentComponent.new do %>
<%= render(UI::SelectItemComponent.new(value: "apple")) { "Apple" } %>
<%= render(UI::SelectItemComponent.new(value: "banana")) { "Banana" } %>
<%= render(UI::SelectItemComponent.new(value: "orange")) { "Orange" } %>
<% end %>
<% end %>With Disabled Items
Some items can be disabled to prevent selection.
<%= render "ui/select" do %>
<%= render "ui/select/trigger", placeholder: "Select a status..." %>
<%= render "ui/select/content" do %>
<%= render "ui/select/item", value: "active" do %>Active<% end %>
<%= render "ui/select/item", value: "pending" do %>Pending<% end %>
<%= render "ui/select/item", value: "archived", disabled: true do %>Archived<% end %>
<% end %>
<% end %><%= render UI::Select.new do %>
<%= render UI::SelectTrigger.new(placeholder: "Select a status...") %>
<%= render UI::SelectContent.new do %>
<%= render UI::SelectItem.new(value: "active") { "Active" } %>
<%= render UI::SelectItem.new(value: "pending") { "Pending" } %>
<%= render UI::SelectItem.new(value: "archived", disabled: true) { "Archived" } %>
<% end %>
<% end %><%= render UI::SelectComponent.new do %>
<%= render UI::SelectTriggerComponent.new(placeholder: "Select a status...") %>
<%= render UI::SelectContentComponent.new do %>
<%= render(UI::SelectItemComponent.new(value: "active")) { "Active" } %>
<%= render(UI::SelectItemComponent.new(value: "pending")) { "Pending" } %>
<%= render(UI::SelectItemComponent.new(value: "archived", disabled: true)) { "Archived" } %>
<% end %>
<% end %>Scrollable
A select with a scrollable list of timezones.
<%= render "ui/select" do %>
<%= render "ui/select/trigger", classes: "w-[280px]", placeholder: "Select a timezone" %>
<%= render "ui/select/content" do %>
<%= render "ui/select/group" do %>
<%= render "ui/select/label" do %>North America<% end %>
<%= render "ui/select/item", value: "est" do %>Eastern Standard Time (EST)<% end %>
<%= render "ui/select/item", value: "cst" do %>Central Standard Time (CST)<% end %>
<%= render "ui/select/item", value: "mst" do %>Mountain Standard Time (MST)<% end %>
<%= render "ui/select/item", value: "pst" do %>Pacific Standard Time (PST)<% end %>
<%= render "ui/select/item", value: "akst" do %>Alaska Standard Time (AKST)<% end %>
<%= render "ui/select/item", value: "hst" do %>Hawaii Standard Time (HST)<% end %>
<% end %>
<%= render "ui/select/group" do %>
<%= render "ui/select/label" do %>Europe & Africa<% end %>
<%= render "ui/select/item", value: "gmt" do %>Greenwich Mean Time (GMT)<% end %>
<%= render "ui/select/item", value: "cet" do %>Central European Time (CET)<% end %>
<%= render "ui/select/item", value: "eet" do %>Eastern European Time (EET)<% end %>
<%= render "ui/select/item", value: "west" do %>Western European Summer Time (WEST)<% end %>
<%= render "ui/select/item", value: "cat" do %>Central Africa Time (CAT)<% end %>
<%= render "ui/select/item", value: "eat" do %>East Africa Time (EAT)<% end %>
<% end %>
<%= render "ui/select/group" do %>
<%= render "ui/select/label" do %>Asia<% end %>
<%= render "ui/select/item", value: "msk" do %>Moscow Standard Time (MSK)<% end %>
<%= render "ui/select/item", value: "ist" do %>India Standard Time (IST)<% end %>
<%= render "ui/select/item", value: "cst_china" do %>China Standard Time (CST)<% end %>
<%= render "ui/select/item", value: "jst" do %>Japan Standard Time (JST)<% end %>
<%= render "ui/select/item", value: "kst" do %>Korea Standard Time (KST)<% end %>
<%= render "ui/select/item", value: "ist_indonesia" do %>Indonesia Central Standard Time (WITA)<% end %>
<% end %>
<%= render "ui/select/group" do %>
<%= render "ui/select/label" do %>Australia & Pacific<% end %>
<%= render "ui/select/item", value: "awst" do %>Australian Western Standard Time (AWST)<% end %>
<%= render "ui/select/item", value: "acst" do %>Australian Central Standard Time (ACST)<% end %>
<%= render "ui/select/item", value: "aest" do %>Australian Eastern Standard Time (AEST)<% end %>
<%= render "ui/select/item", value: "nzst" do %>New Zealand Standard Time (NZST)<% end %>
<%= render "ui/select/item", value: "fjt" do %>Fiji Time (FJT)<% end %>
<% end %>
<%= render "ui/select/group" do %>
<%= render "ui/select/label" do %>South America<% end %>
<%= render "ui/select/item", value: "art" do %>Argentina Time (ART)<% end %>
<%= render "ui/select/item", value: "bot" do %>Bolivia Time (BOT)<% end %>
<%= render "ui/select/item", value: "brt" do %>Brasilia Time (BRT)<% end %>
<%= render "ui/select/item", value: "clt" do %>Chile Standard Time (CLT)<% end %>
<% end %>
<% end %>
<% end %><%= render UI::Select.new do %>
<%= render UI::SelectTrigger.new(classes: "w-[280px]", placeholder: "Select a timezone") %>
<%= render UI::SelectContent.new do %>
<%= render UI::SelectGroup.new do %>
<%= render UI::SelectLabel.new { "North America" } %>
<%= render UI::SelectItem.new(value: "est") { "Eastern Standard Time (EST)" } %>
<%= render UI::SelectItem.new(value: "cst") { "Central Standard Time (CST)" } %>
<%= render UI::SelectItem.new(value: "mst") { "Mountain Standard Time (MST)" } %>
<%= render UI::SelectItem.new(value: "pst") { "Pacific Standard Time (PST)" } %>
<%= render UI::SelectItem.new(value: "akst") { "Alaska Standard Time (AKST)" } %>
<%= render UI::SelectItem.new(value: "hst") { "Hawaii Standard Time (HST)" } %>
<% end %>
<%= render UI::SelectGroup.new do %>
<%= render UI::SelectLabel.new { "Europe & Africa" } %>
<%= render UI::SelectItem.new(value: "gmt") { "Greenwich Mean Time (GMT)" } %>
<%= render UI::SelectItem.new(value: "cet") { "Central European Time (CET)" } %>
<%= render UI::SelectItem.new(value: "eet") { "Eastern European Time (EET)" } %>
<%= render UI::SelectItem.new(value: "west") { "Western European Summer Time (WEST)" } %>
<%= render UI::SelectItem.new(value: "cat") { "Central Africa Time (CAT)" } %>
<%= render UI::SelectItem.new(value: "eat") { "East Africa Time (EAT)" } %>
<% end %>
<%= render UI::SelectGroup.new do %>
<%= render UI::SelectLabel.new { "Asia" } %>
<%= render UI::SelectItem.new(value: "msk") { "Moscow Standard Time (MSK)" } %>
<%= render UI::SelectItem.new(value: "ist") { "India Standard Time (IST)" } %>
<%= render UI::SelectItem.new(value: "cst_china") { "China Standard Time (CST)" } %>
<%= render UI::SelectItem.new(value: "jst") { "Japan Standard Time (JST)" } %>
<%= render UI::SelectItem.new(value: "kst") { "Korea Standard Time (KST)" } %>
<%= render UI::SelectItem.new(value: "ist_indonesia") { "Indonesia Central Standard Time (WITA)" } %>
<% end %>
<%= render UI::SelectGroup.new do %>
<%= render UI::SelectLabel.new { "Australia & Pacific" } %>
<%= render UI::SelectItem.new(value: "awst") { "Australian Western Standard Time (AWST)" } %>
<%= render UI::SelectItem.new(value: "acst") { "Australian Central Standard Time (ACST)" } %>
<%= render UI::SelectItem.new(value: "aest") { "Australian Eastern Standard Time (AEST)" } %>
<%= render UI::SelectItem.new(value: "nzst") { "New Zealand Standard Time (NZST)" } %>
<%= render UI::SelectItem.new(value: "fjt") { "Fiji Time (FJT)" } %>
<% end %>
<%= render UI::SelectGroup.new do %>
<%= render UI::SelectLabel.new { "South America" } %>
<%= render UI::SelectItem.new(value: "art") { "Argentina Time (ART)" } %>
<%= render UI::SelectItem.new(value: "bot") { "Bolivia Time (BOT)" } %>
<%= render UI::SelectItem.new(value: "brt") { "Brasilia Time (BRT)" } %>
<%= render UI::SelectItem.new(value: "clt") { "Chile Standard Time (CLT)" } %>
<% end %>
<% end %>
<% end %><%= render UI::SelectComponent.new do %>
<%= render UI::SelectTriggerComponent.new(classes: "w-[280px]", placeholder: "Select a timezone") %>
<%= render UI::SelectContentComponent.new do %>
<%= render UI::SelectGroupComponent.new do %>
<%= render(UI::SelectLabelComponent.new) { "North America" } %>
<%= render(UI::SelectItemComponent.new(value: "est")) { "Eastern Standard Time (EST)" } %>
<%= render(UI::SelectItemComponent.new(value: "cst")) { "Central Standard Time (CST)" } %>
<%= render(UI::SelectItemComponent.new(value: "mst")) { "Mountain Standard Time (MST)" } %>
<%= render(UI::SelectItemComponent.new(value: "pst")) { "Pacific Standard Time (PST)" } %>
<%= render(UI::SelectItemComponent.new(value: "akst")) { "Alaska Standard Time (AKST)" } %>
<%= render(UI::SelectItemComponent.new(value: "hst")) { "Hawaii Standard Time (HST)" } %>
<% end %>
<%= render UI::SelectGroupComponent.new do %>
<%= render(UI::SelectLabelComponent.new) { "Europe & Africa" } %>
<%= render(UI::SelectItemComponent.new(value: "gmt")) { "Greenwich Mean Time (GMT)" } %>
<%= render(UI::SelectItemComponent.new(value: "cet")) { "Central European Time (CET)" } %>
<%= render(UI::SelectItemComponent.new(value: "eet")) { "Eastern European Time (EET)" } %>
<%= render(UI::SelectItemComponent.new(value: "west")) { "Western European Summer Time (WEST)" } %>
<%= render(UI::SelectItemComponent.new(value: "cat")) { "Central Africa Time (CAT)" } %>
<%= render(UI::SelectItemComponent.new(value: "eat")) { "East Africa Time (EAT)" } %>
<% end %>
<%= render UI::SelectGroupComponent.new do %>
<%= render(UI::SelectLabelComponent.new) { "Asia" } %>
<%= render(UI::SelectItemComponent.new(value: "msk")) { "Moscow Standard Time (MSK)" } %>
<%= render(UI::SelectItemComponent.new(value: "ist")) { "India Standard Time (IST)" } %>
<%= render(UI::SelectItemComponent.new(value: "cst_china")) { "China Standard Time (CST)" } %>
<%= render(UI::SelectItemComponent.new(value: "jst")) { "Japan Standard Time (JST)" } %>
<%= render(UI::SelectItemComponent.new(value: "kst")) { "Korea Standard Time (KST)" } %>
<%= render(UI::SelectItemComponent.new(value: "ist_indonesia")) { "Indonesia Central Standard Time (WITA)" } %>
<% end %>
<%= render UI::SelectGroupComponent.new do %>
<%= render(UI::SelectLabelComponent.new) { "Australia & Pacific" } %>
<%= render(UI::SelectItemComponent.new(value: "awst")) { "Australian Western Standard Time (AWST)" } %>
<%= render(UI::SelectItemComponent.new(value: "acst")) { "Australian Central Standard Time (ACST)" } %>
<%= render(UI::SelectItemComponent.new(value: "aest")) { "Australian Eastern Standard Time (AEST)" } %>
<%= render(UI::SelectItemComponent.new(value: "nzst")) { "New Zealand Standard Time (NZST)" } %>
<%= render(UI::SelectItemComponent.new(value: "fjt")) { "Fiji Time (FJT)" } %>
<% end %>
<%= render UI::SelectGroupComponent.new do %>
<%= render(UI::SelectLabelComponent.new) { "South America" } %>
<%= render(UI::SelectItemComponent.new(value: "art")) { "Argentina Time (ART)" } %>
<%= render(UI::SelectItemComponent.new(value: "bot")) { "Bolivia Time (BOT)" } %>
<%= render(UI::SelectItemComponent.new(value: "brt")) { "Brasilia Time (BRT)" } %>
<%= render(UI::SelectItemComponent.new(value: "clt")) { "Chile Standard Time (CLT)" } %>
<% end %>
<% end %>
<% end %>Features
- Single selection from a list of options
- Keyboard navigation with arrow keys
- Type-ahead search functionality
- Grouped options with labels
- Disabled items support
- Custom trigger with asChild pattern
- Placeholder text when no selection
- Form integration with hidden input
API Reference
Select
Shared behavior for Select component across ERB, ViewComponent, and Phlex implementations.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| value | String | nil | The current value |
Data Attributes
| Attribute | Values | Description |
|---|---|---|
| data-state | open, closed | Current open/closed state |
| data-placeholder | true | Present when showing placeholder |
CSS Variables
| Variable | Description |
|---|---|
| --trigger-width | Width of the trigger element |
Content
Shared behavior for Select dropdown content across ERB, ViewComponent, and Phlex implementations.
Group
Shared behavior for Select options group across ERB, ViewComponent, and Phlex implementations.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| as_child | Boolean | false | When true, yields attributes to block instead of rendering wrapper |
Item
Shared behavior for Individual select option across ERB, ViewComponent, and Phlex implementations.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| as_child | Boolean | false | When true, yields attributes to block instead of rendering wrapper |
| value | String | nil | The current value |
| disabled | Boolean | false | Whether the element is disabled |
Label
Shared behavior for Select group label across ERB, ViewComponent, and Phlex implementations.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| as_child | Boolean | false | When true, yields attributes to block instead of rendering wrapper |
Scroll Down Button
Shared behavior for Select scroll down button across ERB, ViewComponent, and Phlex implementations.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| as_child | Boolean | false | When true, yields attributes to block instead of rendering wrapper |
Scroll Up Button
Shared behavior for Select scroll up button across ERB, ViewComponent, and Phlex implementations.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| as_child | Boolean | false | When true, yields attributes to block instead of rendering wrapper |
Trigger
Shared behavior for Select trigger button across ERB, ViewComponent, and Phlex implementations.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| as_child | Boolean | false | When true, yields attributes to block instead of rendering wrapper |
| placeholder | String | Select... | Placeholder text when no value is selected |
Accessibility
Implements the WAI-ARIA Listbox pattern with proper roles, states, and keyboard navigation.
ARIA Attributes
- role="combobox" on the trigger
- role="listbox" on the content container
- role="option" on each item
- aria-expanded on trigger
- aria-selected on the selected item
- aria-disabled on disabled items
- aria-labelledby for label association
Keyboard Shortcuts
| Key | Description |
|---|---|
| Space | Opens dropdown when trigger is focused |
| Enter | Opens dropdown / selects highlighted item |
| ArrowDown | Opens dropdown / moves to next item |
| ArrowUp | Moves to previous item |
| Home | Moves to first item |
| End | Moves to last item |
| Escape | Closes dropdown |
| A-Z,a-z | Type-ahead to find matching item |
JavaScript
Stimulus Controller
ui--selectValues
| Name | Type | Description |
|---|---|---|
| open | Boolean | Controls open state |
| value | String | Current selected value |
Actions
togglecloseselectItem