# <aihio-date-picker>

A form field for one date (a due date, a birth date, a travel date), typed in the page's language or picked from a month calendar that a button opens under the field. The date submits as YYYY-MM-DD, as a native date input's does. For a date chosen on the page itself, such as a booking day, use aihio-calendar.

Intents: `form-field`, `date-entry`, `text-entry`.

## Attributes

- `value` (string): The initial date as YYYY-MM-DD, whatever the page's language, and the date a form reset returns to. The value property carries the live date.
- `name` (string): Form field name. The date submits under it as YYYY-MM-DD, not as the text on show. Without it the field submits nothing.
- `form` (string): Id of an external form that owns the field.
- `min` (string): The earliest date that can be chosen, as YYYY-MM-DD. Earlier days are struck through in the calendar, and a typed earlier date makes the field invalid.
- `max` (string): The latest date that can be chosen, as YYYY-MM-DD.
- `placeholder` (string): Placeholder text. Defaults to the date format in the page's language, such as mm/dd/yyyy or pp.kk.vvvv. It is not a label.
- `disabled` (boolean): Disables the field and its calendar. A disabled field submits nothing. Default: `false`.
- `readonly` (boolean): Shows the date without letting it change. The date still submits. Default: `false`.
- `required` (boolean): Requires a date for native constraint validation. Default: `false`.
- `error` (boolean): Shows error styling and sets aria-invalid. aihio-field sets this from its error slot. Default: `false`.
- `size` (`sm` | `md` | `lg`): Field size, matching aihio-input. Default: `md`.
- `open` (boolean): Reflects whether the calendar is showing. Set or remove it to open or close the calendar. Default: `false`.
- `autocomplete` (string): Forwarded to the text field. Off by default, so the browser's list of past entries does not cover the calendar; bday lets the browser fill in a birth date. Default: `off`.
- `first-day-of-week` (`mon` | `tue` | `wed` | `thu` | `fri` | `sat` | `sun`): The day the calendar's weeks start on. Defaults to the page's language and region: Monday in Finland, Sunday in the US, Saturday in Egypt. Where lang names no region (en), the browser's region for that language fills it in.
- `choose-text` (string): The calendar button's name and the calendar's, each followed by the field's label. For localisation. Default: `Choose date`.
- `previous-month-text` (string): The previous month button's name. For localisation. Default: `Previous month`.
- `next-month-text` (string): The next month button's name. For localisation. Default: `Next month`.
- `invalid-text` (string): Validation message for text that is not a date, with {format} for the date format (dd.mm.yyyy). For localisation. Default: `Enter a date as {format}.`.
- `min-text` (string): Validation message for a date before min, with {min} for it. For localisation. Default: `Choose {min} or later.`.
- `max-text` (string): Validation message for a date after max, with {max} for it. For localisation. Default: `Choose {max} or earlier.`.
- `unavailable-text` (string): Validation message for a date isDateDisabled rules out, with {date} for it. For localisation. Default: `{date} is not available.`.

## Properties

- `value` (`string`): Get or set the date as YYYY-MM-DD, or "" for none. Anything that is not a date clears it, as with a native date input. Setting it does not fire aihio-change.
- `defaultValue` (`string`): Get or set the reset value reflected by the value attribute.
- `valueAsDate` (`Date | null`): Get or set the date as the UTC midnight it starts at, as a native date input's valueAsDate is.
- `isDateDisabled` (`((date: string) => boolean) | null`): Called with each date the calendar shows, as YYYY-MM-DD. A date it returns true for is struck through and cannot be chosen, and typing it makes the field invalid. Set it again when the dates it rules out change. Read a weekday as new Date(date).getUTCDay().
- `control` (`HTMLInputElement | null`, read-only): The native text field the date is typed into.
- `form` (`HTMLFormElement | null`, read-only): The owning form, or null outside one.
- `validity` (`ValidityState | null`, read-only): Native constraint validation state, including the field's own checks: text that is not a date, a date outside min and max, and one isDateDisabled rules out.
- `validationMessage` (`string`, read-only): Native validation message.
- `willValidate` (`boolean`, read-only): Whether the field participates in constraint validation.

## Methods

- `open()`: Opens the calendar and moves focus into it, on the chosen date or today. Focus goes back to whatever had it when the calendar closes.
- `close()`: Closes the calendar.
- `toggle()`: Opens or closes the calendar.
- `focus()`: Moves focus to the text field.
- `checkValidity()`: Runs native constraint validation and returns whether the field is valid.
- `reportValidity()`: Runs native constraint validation and shows the browser message if invalid.
- `setCustomValidity()`: Sets a custom validation message, which wins over the field's own. An empty message hands validation back to the field.

## Events

- `aihio-change` (detail: value: string): Fired when the person commits a different date: picks one, or leaves the field (or presses Enter) after typing. Text that is not a date commits as "". Also fired when a form reset changes the date, and not for programmatic changes. The native input and change events come from the text field and carry its text.
- `aihio-month` (detail: month: string, start: string, end: string): Fired when the calendar opens, and whenever it shows another month: the month as YYYY-MM, and its first and last day. Fetch the dates to rule out for that month here, then set isDateDisabled again.
- `aihio-open`: Fired after the calendar opens.
- `aihio-close` (detail: reason: string): Fired after the calendar closes, with why: select, escape, outside, blur, toggle, reset, or api.

## Accessibility obligations

- (error, date-picker-label) When the date picker is not inside an aihio-field: Label it with aria-labelledby pointing at visible text, or aria-label. Placeholder is not a label, and a wrapping <label> would fold the open calendar's text into the field's name.
- (warn, date-picker-form-name) When the date picker is inside a <form> and its date should be submitted: Set name. A date picker without a name is omitted from FormData.

## Examples

### In a field

The placeholder shows the date format in the page's language, and the date submits as YYYY-MM-DD.

```html
<aihio-field>
  <label slot="label">Due date</label>
  <aihio-date-picker name="due-date" value="2026-10-30"></aihio-date-picker>
  <span slot="description">Invoices are sent on this day.</span>
</aihio-field>
```

### A range of dates

Days outside min and max are struck through in the calendar, and the months and years it offers stop at them.

```html
<aihio-field>
  <label slot="label">Appointment</label>
  <aihio-date-picker name="appointment" min="2026-10-12" max="2026-12-18" required></aihio-date-picker>
</aihio-field>
```

### A birth date

Most people type it. autocomplete="bday" lets the browser fill it in, and the year select reaches back a century.

```html
<aihio-field>
  <label slot="label">Date of birth</label>
  <aihio-date-picker name="birth-date" autocomplete="bday" max="2026-10-09"></aihio-date-picker>
</aihio-field>
```

### In another language

lang sets how dates are written and read, the names of months and weekdays, and the first day of the week. The text attributes put the rest in the same language.

```html
<aihio-field lang="fi">
  <label slot="label">Eräpäivä</label>
  <aihio-date-picker name="due-date" choose-text="Valitse päivä" previous-month-text="Edellinen kuukausi" next-month-text="Seuraava kuukausi" invalid-text="Kirjoita päivä muodossa {format}." min-text="Valitse {min} tai myöhemmin." max-text="Valitse {max} tai aiemmin." unavailable-text="{date} ei ole valittavissa."></aihio-date-picker>
</aihio-field>
```

## Mistakes

### Placeholder is not a label, and this one hides the date format the field would show there. Put the picker in aihio-field with a label.

Don't (aihio lint: date-picker-label):

```html
<aihio-date-picker placeholder="Due date"></aihio-date-picker>
```

Do:

```html
<aihio-field>
  <label slot="label">Due date</label>
  <aihio-date-picker name="due-date"></aihio-date-picker>
</aihio-field>
```

### A wrapping <label> takes its name from all of its text, so the open calendar's month, weekdays, and days become part of the field's name. Use aihio-field instead.

Don't (aihio lint: date-picker-label):

```html
<label>
  Due date
  <aihio-date-picker name="due-date"></aihio-date-picker>
</label>
```

Do:

```html
<aihio-field>
  <label slot="label">Due date</label>
  <aihio-date-picker name="due-date"></aihio-date-picker>
</aihio-field>
```

### Dates in attributes are YYYY-MM-DD whatever the page's language: 10/09/2026 is 9 October in Finland and 10 September in the US. The field shows the date the page's way.

Don't (aihio lint: date-value):

```html
<aihio-date-picker aria-label="Due date" value="10/09/2026"></aihio-date-picker>
```

Do:

```html
<aihio-date-picker aria-label="Due date" value="2026-10-09"></aihio-date-picker>
```

### min is after max, so there is no date to choose.

Don't (aihio lint: date-range):

```html
<aihio-date-picker aria-label="Check-in" min="2026-12-31" max="2026-01-01"></aihio-date-picker>
```

Do:

```html
<aihio-date-picker aria-label="Check-in" min="2026-01-01" max="2026-12-31"></aihio-date-picker>
```

### Nothing reads format or locale. The field writes and reads dates the way the page's language does: set lang, on the page or the picker.

Don't (aihio lint: unknown-attribute):

```html
<aihio-date-picker aria-label="Start date" format="dd.MM.yyyy" locale="fi"></aihio-date-picker>
```

Do:

```html
<aihio-date-picker aria-label="Alkupäivä" lang="fi"></aihio-date-picker>
```
