# VelvetKit

## Date picker (`UI::DatePicker`)

A typed date field with a calendar, on Cally.

Add it: `bin/rails generate velvetkit:add date_picker`

Also adds: `label`, `form_field`, `icon`

Stimulus: `ui--date-picker`

Installs: `cally`

### Arguments

```ruby
UI::DatePicker.new(name: nil, value: nil, form: nil, field: nil, label: nil, required: false, error: nil, disabled: false, hint: true, min: nil, max: nil, class: nil, **html_attrs)
```

### Notes

UI::DatePicker — a typed date field with a calendar beside it.

Three inputs in one: what the user types (DD/MM/YYYY), what the form submits
(ISO, hidden), and the calendar. The typed field comes first because people
who know the date type it in a second: reaching a date years away in a
calendar means clicking back month after month.

The written format is not decided here. It comes from `date.formats.typed`
in the locale, and this component derives the placeholder, the parse order
and the separator from that one string — so a locale that writes dates
differently changes what the field accepts, what it shows and what the hint
says, together, with nothing hardcoded.

The shipped English format is day-first; change `date.formats.typed` for
month-first. A native date input follows the browser's locale instead, which
is how the same form reads MM/DD on one machine and DD/MM on another, and how
the 2nd of May gets recorded as the 5th of February.

Cally is ~9 KB gzipped and loaded only when the calendar is first opened, so
a form nobody opens a calendar on downloads nothing.

Usage:
  <%= render(UI::DatePicker.new(form: f, field: :starts_on, required: true)) %>
  <%= render(UI::DatePicker.new(name: "event[date]", value: @date, label: "Date")) %>

### Example: Default

```erb
<div class="max-w-xs">
  <%= render(UI::DatePicker.new(name: "event[date]", label: "Date of birth", value: Date.new(2012, 5, 2))) %>
</div>
```

### Example: States

```erb
<div class="flex max-w-xs flex-col gap-6">
  <%= render(UI::DatePicker.new(name: "a", label: "Empty")) %>
  <%= render(UI::DatePicker.new(name: "b", label: "Required", required: true)) %>
  <%= render(UI::DatePicker.new(name: "c", label: "With an error", error: true, value: Date.new(2026, 10, 21))) %>
  <%= render(UI::DatePicker.new(name: "d", label: "Disabled", disabled: true, value: Date.new(2026, 10, 21))) %>
  <%= render(UI::DatePicker.new(name: "e", label: "Without the hint", hint: false)) %>
</div>
```
