Select
Displays a list of options for the user to pick from—triggered by a button.
<%= render(Shadcn::SelectComponent.new(name: "fruit", placeholder: "Select a fruit")) do |select| %>
<% select.with_item(value: "apple") { "Apple" } %>
<% select.with_item(value: "banana") { "Banana" } %>
<% select.with_item(value: "orange") { "Orange" } %>
<% select.with_item(value: "grape") { "Grape" } %>
<% select.with_item(value: "strawberry") { "Strawberry" } %>
<% end %>
Installation
Add the component to your project:
rails generate shadcn:add select
Usage
<%= render(Shadcn::SelectComponent.new(name: "fruit", placeholder: "Select a fruit")) do |select| %>
<% select.with_item(value: "apple") { "Apple" } %>
<% select.with_item(value: "banana") { "Banana" } %>
<% select.with_item(value: "orange") { "Orange" } %>
<% select.with_item(value: "grape") { "Grape" } %>
<% select.with_item(value: "strawberry") { "Strawberry" } %>
<% end %>
Examples
With Groups
Organize options into labeled groups.
<%= render Shadcn::SelectComponent.new(name: "timezone", placeholder: "Select a timezone", class_name: "w-[200px]") do |select| %>
<% select.with_group(label: "North America") do |group| %>
<% group.with_item(value: "est") { "Eastern Time" } %>
<% group.with_item(value: "cst") { "Central Time" } %>
<% group.with_item(value: "mst") { "Mountain Time" } %>
<% group.with_item(value: "pst") { "Pacific Time" } %>
<% end %>
<% select.with_group(label: "Europe") do |group| %>
<% group.with_item(value: "gmt") { "Greenwich Mean Time" } %>
<% group.with_item(value: "cet") { "Central European Time" } %>
<% end %>
<% end %>
Preselected Value
Set an initial value with the value parameter.
<%= render Shadcn::Select.new(
name: "fruit",
value: "banana",
placeholder: "Select a fruit",
class_name: "w-[180px]"
) do |select| %>
<% select.with_item(value: "apple") { "Apple" } %>
<% select.with_item(value: "banana") { "Banana" } %>
<% select.with_item(value: "orange") { "Orange" } %>
<% end %>
Disabled State
Disable the entire select component.
<%= render Shadcn::SelectComponent.new(name: "fruit", placeholder: "Select a fruit", disabled: true, class_name: "w-[180px]") do |select| %>
<% select.with_item(value: "apple") { "Apple" } %>
<% select.with_item(value: "banana") { "Banana" } %>
<% select.with_item(value: "orange") { "Orange" } %>
<% end %>
Disabled Items
Disable specific items within the select.
<%= render Shadcn::SelectComponent.new(name: "fruit", placeholder: "Select a fruit", class_name: "w-[180px]") do |select| %>
<% select.with_item(value: "apple") { "Apple" } %>
<% select.with_item(value: "banana", disabled: true) { "Banana (out of stock)" } %>
<% select.with_item(value: "orange") { "Orange" } %>
<% select.with_item(value: "grape", disabled: true) { "Grape (out of stock)" } %>
<% select.with_item(value: "pineapple") { "Pineapple" } %>
<% end %>
Form Integration
Use Select within forms with proper labels and validation.
<%= form_with url: "#", method: :post, class: "flex flex-col gap-4" do |f| %>
<div class="flex flex-col gap-2">
<%= render Shadcn::Label.new(for: "country") { "Country" } %>
<%= render Shadcn::Select.new(
name: "country",
id: "country",
placeholder: "Select your country",
required: true,
class_name: "w-[200px]"
) do |select| %>
<% select.with_item(value: "us") { "United States" } %>
<% select.with_item(value: "uk") { "United Kingdom" } %>
<% select.with_item(value: "ca") { "Canada" } %>
<% select.with_item(value: "au") { "Australia" } %>
<% end %>
</div>
<%= render Shadcn::Button.new(type: :submit) { "Submit" } %>
<% end %>
With Default Value
<%= render(Shadcn::SelectComponent.new(name: "timezone", value: "est", placeholder: "Select a timezone")) do |select| %>
<% select.with_item(value: "est") { "Eastern Standard Time (EST)" } %>
<% select.with_item(value: "cst") { "Central Standard Time (CST)" } %>
<% select.with_item(value: "mst") { "Mountain Standard Time (MST)" } %>
<% select.with_item(value: "pst") { "Pacific Standard Time (PST)" } %>
<% end %>
Disabled Options
<%= render(Shadcn::SelectComponent.new(name: "plan", placeholder: "Select a plan")) do |select| %>
<% select.with_item(value: "free") { "Free" } %>
<% select.with_item(value: "starter") { "Starter" } %>
<% select.with_item(value: "pro") { "Pro" } %>
<% select.with_item(value: "enterprise", disabled: true) { "Enterprise (Coming Soon)" } %>
<% end %>
Disabled Select
<%= render(Shadcn::SelectComponent.new(name: "status", disabled: true, placeholder: "Select status")) do |select| %>
<% select.with_item(value: "active") { "Active" } %>
<% select.with_item(value: "inactive") { "Inactive" } %>
<% select.with_item(value: "pending") { "Pending" } %>
<% end %>
Required Field
<%= render(Shadcn::SelectComponent.new(name: "country", required: true, placeholder: "Select a country")) do |select| %>
<% select.with_item(value: "us") { "United States" } %>
<% select.with_item(value: "ca") { "Canada" } %>
<% select.with_item(value: "uk") { "United Kingdom" } %>
<% select.with_item(value: "au") { "Australia" } %>
<% end %>
Framework Selection
<%= render(Shadcn::SelectComponent.new(name: "framework", placeholder: "Select a framework", class_name: "w-[280px]")) do |select| %>
<% select.with_item(value: "next") { "Next.js" } %>
<% select.with_item(value: "sveltekit") { "SvelteKit" } %>
<% select.with_item(value: "nuxt") { "Nuxt.js" } %>
<% select.with_item(value: "remix") { "Remix" } %>
<% select.with_item(value: "astro") { "Astro" } %>
<% select.with_item(value: "rails") { "Ruby on Rails" } %>
<% end %>
Email Provider
<%= render(Shadcn::SelectComponent.new(name: "email", value: "gmail", placeholder: "Select email")) do |select| %>
<% select.with_group(label: "Personal") do |group| %>
<% group.with_item(value: "gmail") { "Gmail" } %>
<% group.with_item(value: "yahoo") { "Yahoo Mail" } %>
<% group.with_item(value: "outlook") { "Outlook" } %>
<% group.with_item(value: "icloud") { "iCloud Mail" } %>
<% end %>
<% select.with_group(label: "Business") do |group| %>
<% group.with_item(value: "gsuite") { "Google Workspace" } %>
<% group.with_item(value: "office365") { "Microsoft 365" } %>
<% group.with_item(value: "zoho") { "Zoho Mail" } %>
<% end %>
<% end %>
Long List
<%= render Shadcn::Select.new(name: "number", placeholder: "Select a number") do |select| %>
<% select.with_item(value: "1") { "Option 1" } %>
<% select.with_item(value: "2") { "Option 2" } %>
<% select.with_item(value: "3") { "Option 3" } %>
<% select.with_item(value: "4") { "Option 4" } %>
<% select.with_item(value: "5") { "Option 5" } %>
<% select.with_item(value: "6") { "Option 6" } %>
<% select.with_item(value: "7") { "Option 7" } %>
<% select.with_item(value: "8") { "Option 8" } %>
<% select.with_item(value: "9") { "Option 9" } %>
<% select.with_item(value: "10") { "Option 10" } %>
<% select.with_item(value: "11") { "Option 11" } %>
<% select.with_item(value: "12") { "Option 12" } %>
<% select.with_item(value: "13") { "Option 13" } %>
<% select.with_item(value: "14") { "Option 14" } %>
<% select.with_item(value: "15") { "Option 15" } %>
<% select.with_item(value: "16") { "Option 16" } %>
<% select.with_item(value: "17") { "Option 17" } %>
<% select.with_item(value: "18") { "Option 18" } %>
<% select.with_item(value: "19") { "Option 19" } %>
<% select.with_item(value: "20") { "Option 20" } %>
<% select.with_item(value: "21") { "Option 21" } %>
<% select.with_item(value: "22") { "Option 22" } %>
<% select.with_item(value: "23") { "Option 23" } %>
<% select.with_item(value: "24") { "Option 24" } %>
<% select.with_item(value: "25") { "Option 25" } %>
<% select.with_item(value: "26") { "Option 26" } %>
<% select.with_item(value: "27") { "Option 27" } %>
<% select.with_item(value: "28") { "Option 28" } %>
<% select.with_item(value: "29") { "Option 29" } %>
<% select.with_item(value: "30") { "Option 30" } %>
<% select.with_item(value: "31") { "Option 31" } %>
<% select.with_item(value: "32") { "Option 32" } %>
<% select.with_item(value: "33") { "Option 33" } %>
<% select.with_item(value: "34") { "Option 34" } %>
<% select.with_item(value: "35") { "Option 35" } %>
<% select.with_item(value: "36") { "Option 36" } %>
<% select.with_item(value: "37") { "Option 37" } %>
<% select.with_item(value: "38") { "Option 38" } %>
<% select.with_item(value: "39") { "Option 39" } %>
<% select.with_item(value: "40") { "Option 40" } %>
<% select.with_item(value: "41") { "Option 41" } %>
<% select.with_item(value: "42") { "Option 42" } %>
<% select.with_item(value: "43") { "Option 43" } %>
<% select.with_item(value: "44") { "Option 44" } %>
<% select.with_item(value: "45") { "Option 45" } %>
<% select.with_item(value: "46") { "Option 46" } %>
<% select.with_item(value: "47") { "Option 47" } %>
<% select.with_item(value: "48") { "Option 48" } %>
<% select.with_item(value: "49") { "Option 49" } %>
<% select.with_item(value: "50") { "Option 50" } %>
<% end %>
In Form Layout
<%= render(Shadcn::SelectComponent.new(name: "role", placeholder: "Select a role")) do |select| %>
<% select.with_item(value: "developer") { "Developer" } %>
<% select.with_item(value: "designer") { "Designer" } %>
<% select.with_item(value: "manager") { "Manager" } %>
<% select.with_item(value: "owner") { "Owner" } %>
<% end %>
API Reference
SelectComponent
| Prop | Type | Default | Description |
|---|---|---|---|
| name |
String
|
nil
|
Form field name for the hidden input |
| id |
String
|
nil
|
Element ID for the hidden input |
| value |
String
|
nil
|
Currently selected value |
| placeholder |
String
|
"Select..."
|
Placeholder text shown when no value is selected |
| disabled |
Boolean
|
false
|
Whether the select is disabled |
| required |
Boolean
|
false
|
Whether the select is required for form validation |
Slots
| Slot | Props | Description |
|---|---|---|
| with_item | value:, disabled: |
A selectable option (yields content) |
| with_group | label: |
A group of options with an optional label (yields SelectGroupComponent) |
SelectItemComponent
| Prop | Type | Default | Description |
|---|---|---|---|
| value |
String
|
required
|
The value submitted when this option is selected |
| disabled |
Boolean
|
false
|
Whether this option is disabled |
SelectGroupComponent
| Prop | Type | Default | Description |
|---|---|---|---|
| label |
String
|
nil
|
Optional label for the group |
The SelectGroupComponent also accepts with_item slots for items within the group.
Stimulus Controller
This component requires JavaScript. The Stimulus controller shadcn--select provides interactivity.
Manages select dropdown state, keyboard navigation, value selection, and accessibility.
Installation
Add to your config/importmap.rb:
pin "shadcn", to: "index.esm.js"
Then in your app/javascript/controllers/index.js:
import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn"
const application = Application.start()
registerShadcnControllers(application)
Install the package:
npm install shadcn-rails-stimulus
Then in your app/javascript/controllers/index.js:
import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn-rails-stimulus"
const application = Application.start()
registerShadcnControllers(application)
Install the package:
yarn add shadcn-rails-stimulus
Then in your app/javascript/controllers/index.js:
import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn-rails-stimulus"
const application = Application.start()
registerShadcnControllers(application)
Install the package:
npm install shadcn-rails-stimulus
Then in your app/javascript/controllers/index.js:
import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn-rails-stimulus"
const application = Application.start()
registerShadcnControllers(application)
Or import just this controller:
import SelectController from "shadcn-rails-stimulus/controllers/select_controller"
application.register("shadcn--select", SelectController)
Targets
| Name | Description |
|---|---|
| trigger | The button that toggles the dropdown |
| content | The dropdown content container |
| input | The hidden input that stores the selected value |
| item | Each selectable option in the dropdown |
| display | The text display showing the current selection |
| checkIcon | The checkmark icon for selected items |
Values
| Name | Type | Default | Description |
|---|---|---|---|
| value | String |
""
|
Currently selected value |
Actions
| Action | Description |
|---|---|
| toggle | Opens or closes the dropdown |
| open | Opens the dropdown |
| close | Closes the dropdown |
| select | Selects an item from the dropdown |
| handleKeydown | Handles keyboard navigation (Arrow keys, Enter, Escape, Home, End) |
TypeScript
Type definitions are included. Import types as needed:
import type { SelectController } from "shadcn-rails-stimulus"
Accessibility
- Uses
role="combobox"on the trigger for proper screen reader announcement - Uses
role="listbox"for the dropdown content - Uses
role="option"for each selectable item - Sets
aria-expandedto indicate dropdown open/closed state - Sets
aria-selectedto indicate selected option - Supports full keyboard navigation:
- Space or Enter to open/select
- Arrow Down / Arrow Up to navigate options
- Home / End to jump to first/last option
- Escape to close dropdown
- Disabled items are properly marked and skipped during keyboard navigation
- Focus returns to trigger after selection or closing
- Visual checkmark indicator for the selected option
On This Page