Date Field
A segmented input for typing a date one part at a time.
Installation
Included in poetry-ui — available as
poetry_date_field
the moment you've installed Poetry,
with no per-component step. To own the source and edit it, copy it into your app:
bin/rails g poetry:add date-field
Default
<%= poetry_date_field(name: "event[on]", label: "Event date", value: Date.new(2026, 3, 9), class: "w-64") %>
With range
<%# min/max ride the native input - constraint validation stays on
with or without JS. %>
<%= poetry_date_field(name: "booking[night]", label: "First night",
min: Date.new(2026, 1, 1), max: Date.new(2026, 12, 31), class: "w-64") %>
Year first
<%# Segment order follows the field's locale. Pass locale: to pin one -
en-CA writes ISO year-month-day, so the segments rearrange
themselves. The submitted value is ISO yyyy-mm-dd in every locale. %>
<%= poetry_date_field(name: "report[generated_on]", label: "Generated on", locale: "en-CA",
value: Date.new(2026, 3, 9), class: "w-64") %>
API
Poetry::Ui::DateField::Component — options are
constructor keywords (the poetry_* helper forwards them);
slots are composed inside the block. Generated from the gem's source documentation.
| Option | Type | Details | Description |
|---|---|---|---|
| described_by: | String | Ids for aria-describedby (hint or error text). | |
| disabled: | Boolean | defaults to false |
Disables the field; the segment group dims and goes inert. |
| id: | String | The native input's DOM id - the Field label target. | |
| invalid: | Boolean | defaults to false |
Paints the destructive border/ring and sets aria-invalid. |
| label: | String | Standalone accessible name; inside a form the Field label wires ids instead. Segments announce it themselves. | |
| locale: | String | Pins the field to a locale other than the page's. | |
| max: | Object | The latest allowed date (Date or ISO string) - rides native constraint validation. | |
| min: | Object | The earliest allowed date (Date or ISO string) - rides native constraint validation. | |
| name: | String | required | The form field name - required; the value posts as ISO yyyy-mm-dd with or without JS. |
| placeholder_value: | Object | What the first arrow press on an empty segment lands on; defaults to today. | |
| readonly: | Boolean | defaults to false |
The value shows but cannot be edited. |
| required: | Boolean | defaults to false |
Marks the native input required. |
| value: | Object | Date, or an ISO yyyy-mm-dd string; nil renders empty. |
Styling
Every part carries a stable data-slot attribute — target
[data-slot=…] from your own CSS to restyle it. State rides
data attributes on the parts below. This contract is verified against rendered DOM in CI.
| Part | Description |
|---|---|
| [data-slot=date-field] | Root - the controller and the enhanced/disabled surface ride here |
| [data-slot=date-field-group] | The bordered segment row (cn-input chrome, focus-within ring) - hidden until enhancement, then the editing surface the controller fills with segments |
| [data-slot=date-field-input] | The native <input type=date> - THE form value in both modes; tabindex -1 + aria-hidden once segments exist |
State attributes
| Part | Attribute | Condition | Values |
|---|---|---|---|
| date-field | data-enhanced | the controller connected and built segments (no JS = the native input, visible and styled) | — |
| date-field | data-disabled | disabled: is set | — |
| date-field | data-invalid | invalid: is set (the group wears the destructive ring) | — |
| date-field-group | data-disabled | disabled: is set (chrome dims, pointer events off) | — |
| date-field-group | data-invalid | invalid: is set (destructive border + ring) | — |
Wiring
The Stimulus surface each element carries — declared in the component, verified against rendered DOM in CI. Bare actions fire on the element's default event.
| Element | Controller | Wiring |
|---|---|---|
| root | poetry--core--date-field | registers · value locale (if) · value placeholder · value labels · value placeholders |
| group | poetry--core--date-field | focusGap on click · settle on focusout · target group |
| input | poetry--core--date-field | target input |