Date Picker
A date field that opens a calendar popover for selection.
Installation
Included in poetry-ui — available as
poetry_date_picker
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-picker
Default
<%= poetry_date_picker(name: "due_on", label: "Due date") %>
Date of birth
<%= poetry_date_picker(name: "date_of_birth", label: "Date of birth",
placeholder: "Select your birth date",
caption_layout: :dropdown,
min: "1920-01-01", max: "2008-12-31",
month: "1990-01-01") %>
Input
<%# variant: :input - a text field with a calendar button. Typing a
parseable date ("June 20, 2026") re-selects the calendar; picking
writes the formatted date back. ArrowDown opens the calendar. The
submitted value stays ISO on the hidden field either way. %>
<div class="w-64">
<%= poetry_date_picker(name: "subscription[on]", variant: :input,
label: "Subscription date", placeholder: "June 1, 2026",
value: "2026-06-01") %>
</div>
Preselected
<%= poetry_date_picker(name: "due_on", label: "Due date",
value: "2026-06-12", month: "2026-06-01") %>
Range
<%= poetry_date_picker(name: "stay", mode: :range, label: "Stay dates",
placeholder: "Pick a date range",
value: %w[2026-06-09 2026-06-18], month: "2026-06-01") %>
With time
<%# The date-and-time pair: a DatePicker beside a TimeField, each under
its own label. Two form fields - the date submits ISO from the picker,
the time from the segmented field. The picker's accessible name is its
label: option (for_id: nil is the group-label form). %>
<div class="flex items-end gap-4">
<div class="flex flex-col gap-2">
<%= poetry_label(for_id: nil) { "Date" } %>
<%= poetry_date_picker(name: "meeting[on]", label: "Meeting date",
placeholder: "Select date", value: "2026-06-12", month: "2026-06-01") %>
</div>
<div class="flex flex-col gap-2">
<%= poetry_label(for_id: "meeting-time") { "Time" } %>
<%= poetry_time_field(name: "meeting[at]", id: "meeting-time", label: "Meeting time",
value: "10:30", class: "w-32") %>
</div>
</div>
API
Poetry::Ui::DatePicker::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 |
|---|---|---|---|
| caption_layout: | Symbol | defaults to :label |
Forwarded to the wrapped Calendar: :dropdown swaps the caption for month + year selects (the date-of-birth recipe - min:/max: bound the year list). |
| label: | String | The trigger's accessible name (aria-label). | |
| mode: | Symbol | defaults to :single |
:single or :range (two-date selection; the trigger shows the joined pair). |
| name: | String | required | The form field name - required; the chosen date posts as ISO. |
| placeholder: | String | defaults to "Pick a date" |
Trigger text while nothing is chosen. |
| variant: | Symbol | defaults to :button |
:button (the default trigger) or :input - a text field that accepts a typed date (parseable text re-selects the calendar) with a calendar icon-button opening the popover. Single mode only. |
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-picker] | Root wrapper - the glue controller (formats the trigger label, closes on pick) around the composed Popover + Calendar |
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-picker | registers · value placeholder · value mode (if range?) · picked on poetry:calendar:change |
| label | poetry--core--date-picker | target label |
| input | poetry--core--date-picker | inputChanged on input · inputKeydown on keydown · target input |