Input
Native input controls with explicit HTML semantics.
- Source
app/components/nitro_kit/input.rb- API
NitroKit::Input.new(type:, id:, name:, value:)
Native types
Representative browser types keep native value, completion, placeholder, and requirement semantics.
Type matrix
test/dummy/app/components/gallery/components/input_page.rbGallery::Data.input_examples.each do |input|
sample(input.label, slug: input.slug) do
render_input(input)
end
endSpecialized controls
Boolean, file, and range controls retain their browser-specific attributes.
Specialized types
test/dummy/app/components/gallery/components/input_page.rbsample("Checked checkbox", slug: "checkbox") do
render NitroKit::Input.new(
type: :checkbox,
id: "gallery-input-checkbox",
name: "preferences[weekly_digest]",
value: "1",
checked: true,
aria: { label: "Send weekly digest" }
)
end
sample("File upload", slug: "file") do
render NitroKit::Input.new(
type: :file,
id: "gallery-input-file",
name: "profile[avatar]",
accept: "image/png,image/jpeg",
aria: { label: "Profile image" }
)
end
sample("Range", slug: "range") do
render NitroKit::Input.new(
type: :range,
id: "gallery-input-range",
name: "notifications[volume]",
value: 60,
min: 0,
max: 100,
step: 10,
aria: { label: "Notification volume" }
)
endDate controls
Date selection is an ordinary native input with server-verifiable constraints and normalized cross-browser alignment.
Date matrix
test/dummy/app/components/gallery/components/input_page.rbsample("Empty", slug: "empty") do
render_date("gallery-input-date-empty", aria: { label: "Start date" })
end
sample("Selected", slug: "selected") do
render_date(
"gallery-input-date-selected",
value: Date.new(2026, 7, 13),
aria: { label: "Start date" }
)
end
sample("Required range", slug: "required-range") do
render_date(
"gallery-input-date-required",
min: Date.new(2026, 7, 13),
max: Date.new(2026, 8, 13),
required: true,
aria: { label: "Deployment date" }
)
end
sample("Read only", slug: "readonly") do
render_date(
"gallery-input-date-readonly",
value: Date.new(2026, 7, 13),
readonly: true,
aria: { label: "Invoice date" }
)
end
sample("Disabled", slug: "disabled") do
render_date(
"gallery-input-date-disabled",
value: Date.new(2026, 7, 13),
disabled: true,
aria: { label: "Archived date" }
)
endSchedule a release
test/dummy/app/components/gallery/components/input_page.rbrender NitroKit::Card.new(id: "gallery-input-date-release-card") do |card|
card.title("Schedule production release", level: 3)
card.body do
form(id: "gallery-input-date-release-form", action: "/gallery/releases", method: "post") do
render NitroKit::FieldGroup.new do
render NitroKit::Field.new(
nil,
:release_date,
as: :date,
id: "gallery-input-date-release-date",
name: "release[date]",
label: "Release date",
description: "Choose a weekday within the next thirty days.",
value: Date.new(2026, 7, 20),
min: Date.new(2026, 7, 13),
max: Date.new(2026, 8, 12),
required: true
)
render NitroKit::Button.new(
"Schedule release",
id: "gallery-input-date-schedule",
type: :submit,
variant: :primary
)
end
end
end
endMonth and ISO week
Native month and week types are progressive enhancement. The server must validate YYYY-MM or YYYY-Www and all range rules.
test/dummy/app/components/gallery/components/input_page.rbsample("Native month", slug: "month") do
render NitroKit::Field.new(
nil,
:billing_month,
as: :month,
id: "gallery-input-month",
name: "billing[month]",
value: "2026-08",
label: "Billing month",
description: "Enter YYYY-MM if your browser does not provide a picker.",
min: "2026-01",
max: "2026-12",
required: true
)
end
sample("Native ISO week", slug: "week") do
render NitroKit::Field.new(
nil,
:delivery_week,
as: :week,
id: "gallery-input-week",
name: "delivery[week]",
value: "2026-W32",
label: "Delivery week",
description: "Enter YYYY-Www if your browser does not provide a picker.",
required: true
)
end
sample("Exact month choice", slug: "month-select") do
render NitroKit::Field.new(
nil,
:reporting_month,
as: :select,
id: "gallery-input-month-select",
name: "report[month]",
value: "2026-08",
label: "Reporting month",
description: "Use explicit application-owned options when only these periods are valid.",
options: [ [ "July 2026", "2026-07" ], [ "August 2026", "2026-08" ] ]
)
endValidation and availability
Required, invalid, read-only, and disabled state remains inspectable in native attributes.
Control states
Enter a valid email address
test/dummy/app/components/gallery/components/input_page.rbsample("Invalid", slug: "invalid") do
render NitroKit::Input.new(
type: :email,
id: "gallery-input-invalid",
name: "billing[email]",
value: "not-an-email",
required: true,
aria: { label: "Billing email", invalid: true, describedby: "gallery-input-invalid-error" }
)
p(id: "gallery-input-invalid-error") { "Enter a valid email address" }
end
sample("Length limited", slug: "length") do
render NitroKit::Input.new(
id: "gallery-input-length",
name: "workspace[slug]",
value: "mothership",
minlength: 3,
maxlength: 24,
aria: { label: "Workspace slug" }
)
end
sample("Read only", slug: "readonly") do
render NitroKit::Input.new(
id: "gallery-input-readonly",
value: "acct_42NK",
readonly: true,
aria: { label: "Account identifier" }
)
end
sample("Disabled", slug: "disabled") do
render NitroKit::Input.new(
id: "gallery-input-disabled-state",
value: "Unavailable",
disabled: true,
aria: { label: "Legacy setting" }
)
endComponent contract
Constructor options, rendered root, closed vocabularies, and compound boundary for this component, exactly as shipped.
docs/component_contracts.md · NitroKit::Input
- Constructor-specific options
type: :text,id: nil,name: nil,value: nil,placeholder: nil,disabled: false,readonly: false,required: false,autocomplete: nil,min: nil,max: nil,step: nil,minlength: nil,maxlength: nil,multiple: false,accept: nil,pattern: nil,inputmode: nil,checked: nil
- Root and closed vocabulary
- native
input[data-nk=input]; typesbutton checkbox color date datetime-local email file hidden month number password radio range search tel text time url week - Contract
- Every owned attribute is a keyword; passing one through
html:raises and names the keyword.type: :filewith avalue:raises. Boolean attributes and length constraints are validated; minimum length cannot exceed maximum. Read-only controls have their own muted treatment.datereceives the Safari editor-alignment fix.monthandweekretain their native types only as progressive enhancement: browsers may expose text entry without picker, normalization, ormin/max/stepenforcement. Applications must server-validateYYYY-MMorYYYY-Wwwplus range and step rules, and should compose an application-ownedSelectfor exact bounded choices.
Relevant patterns
Application conventions this component belongs to. Each summary is the leading section of its pattern document.
docs/patterns/resource_form.md
Resource form
- One model-backed Phlex component renders initial and invalid states.
- Rails owns names, values, and errors; Nitro owns presentation.
- Invalid mutations render the same model with
422; success redirects with303. - Use one primary submit: the shell toolbar owns it, or a standalone form keeps it inside
form.group. - Wrap the form in a Turbo Frame only when it needs an independent lifecycle.
System rules for coding agents
Instructions for coding agents, repeated on every component page so one fetched page has enough context. Humans can usually skip this section.
test/dummy/app/components/gallery/agent_rules.rb
View agent instructions
- Nitro Kit 2.0 is a gem-owned, Phlex-only UI system for Rails. Render components directly:
render NitroKit::Button.new("Save", variant: :primary). - Compose Nitro components inside application-owned Phlex classes. Public initializers and declared slots are the component API; private methods are not.
- Public options are explicit keywords, and enumerated options are closed vocabularies. Invalid names or values raise
ArgumentError; this component's accepted options are in the contract above. - Pass native attributes through their typed boundary:
html:for HTML,aria:for ARIA, anddata:for application data.classandstyleare forbidden, including insidehtml:. - Nitro owns
NitroKit::Component::RESERVED_DATA_ATTRIBUTES:data-nk,data-slot,data-variant,data-size,data-nk-escape,data-enhanced,data-state,data-disabled,data-required,data-orientation,data-presentation,data-placement,data-layout,data-side,data-field-type,data-dir,data-gap,data-align,data-justify,data-wrap,data-cols,data-mode,data-key. Do not pass them throughdata:.data-action,data-controllerare additive and compose with Nitro behavior. - If an integration truly requires a class, use
desperately_need_a_class:. It requires a non-blank String and marks the exception withdata-nk-escape="class". - Every root emits
data-nk; owned parts emit component-qualifieddata-slotvalues such asfield-controlorcard-title. Select on those attributes, never on classes. - Customize components with documented
--nk-*custom properties in an application stylesheet. Variables beginning with--_nk-*are private component mechanics. - Use
NitroKit::FlexandNitroKit::Gridfor layout. Parents own external placement and available width; components own their intrinsic geometry. - Preserve native elements and accessibility semantics. State is exposed through native semantics and ARIA first, and through
data-statewhen styling or behavior also needs it.