Native selection controls with typed choices, prompts, blanks, and multiple values.
app/components/nitro_kit/select.rbNitroKit::Select.new(options:, id:, name:, value:, multiple:)Strings, arrays, hashes, and Choice records normalize into the same explicit option contract.
test/dummy/app/components/gallery/components/select_page.rbrender NitroKit::Select.new(
id: "gallery-select-mixed-control",
control_aria: { label: "Workspace region" },
name: "workspace[region]",
value: "eu-central",
include_blank: "No region selected",
options: [
"Automatic",
[ "United States East", "us-east" ],
{ label: "European Union Central", value: "eu-central", id: "region-eu-central" },
NitroKit::Choice.new(
label: "Legacy Asia Pacific",
value: "ap-legacy",
disabled: true,
id: "region-ap-legacy"
)
],
html: { id: "gallery-select-mixed" }
)test/dummy/app/components/gallery/components/select_page.rbsample("Prompt", slug: "prompt") do
render NitroKit::Select.new(
id: "gallery-select-prompt-control",
control_aria: { label: "Member role" },
name: "member[role]",
prompt: "Choose a role",
required: true,
options: [ [ "Administrator", "admin" ], [ "Member", "member" ], [ "Viewer", "viewer" ] ],
html: { id: "gallery-select-prompt" }
)
end
sample("No choices", slug: "empty") do
render NitroKit::Select.new(
id: "gallery-select-empty-control",
control_aria: { label: "Available region" },
name: "workspace[available_region]",
options: [],
disabled: true,
aria: { label: "No regions available" },
html: { id: "gallery-select-empty" }
)
endSingle, multiple, disabled, and long choices retain native names and selected values.
test/dummy/app/components/gallery/components/select_page.rbsample("Multiple", slug: "multiple") do
render NitroKit::Select.new(
id: "gallery-select-multiple-control",
control_aria: { label: "Notification channels" },
name: "notifications[channels]",
value: %w[email security],
multiple: true,
options: [
[ "Product updates", "product" ],
[ "Email summaries", "email" ],
[ "Security notices", "security" ]
],
html: { id: "gallery-select-multiple" }
)
end
sample("Disabled", slug: "disabled") do
render NitroKit::Select.new(
id: "gallery-select-disabled-control",
control_aria: { label: "Billing currency" },
name: "billing[currency]",
value: "USD",
disabled: true,
options: [ [ "United States dollar", "USD" ], [ "Euro", "EUR" ] ],
html: { id: "gallery-select-disabled" }
)
end
sample("Long option", slug: "long") do
render NitroKit::Select.new(
id: "gallery-select-long-control",
control_aria: { label: "Retention policy" },
name: "retention[policy]",
value: "regulated",
options: [
[ "Standard retention for ordinary workspace activity", "standard" ],
[ "Extended regulated retention with immutable audit exports", "regulated" ]
],
html: { id: "gallery-select-long" }
)
endThe builder preserves model selection, Rails field names, prompts, and validation errors.
test/dummy/app/components/gallery/components/select_page.rbprofile = Gallery::FormExamples.profile(:invalid)
form_with(
model: profile,
scope: :profile,
url: "#profile-time-zone",
builder: NitroKit::FormBuilder,
id: "gallery-select-profile-form"
) do |form|
form.field(
:time_zone,
as: :select,
id: "gallery-select-profile-time-zone",
label: "Time zone",
description: "Dates in reports use this display time zone.",
prompt: "Choose a time zone",
options: Gallery::Forms::Profile::TIME_ZONES,
required: true
)
form.submit("Save time zone", id: "gallery-select-profile-save")
end