---
title: "DatePicker"
description: "A date field with an anchored panel, not portalled. It covers single dates and ranges, formats with Intl and returns Date through onValueChange; the application stores ISO 8601 and converts it at render time."
kind: component
id: C-064
registry: "date-picker"
docs: "https://koten.codehive.com.co/components/date-picker"
markdown: "https://koten.codehive.com.co/md/components/date-picker.md"
install: "npx shadcn@latest add https://koten.codehive.com.co/r/date-picker.json"
language: en
---

# DatePicker · 日付選択

> Component C-064 in the Koten UI catalog.

A date field with an anchored panel, not portalled. It covers single dates and ranges, formats with Intl and returns Date through onValueChange; the application stores ISO 8601 and converts it at render time.

> Japanese labels in this page are documentation metadata. Keep the consumer UI in the product's language and do not add Japanese decoration unless the user asks (R-031).

## Install

Install `koten-theme` first when the project does not have Koten tokens yet. Use the runner of your project.

```bash
# Node
npx shadcn@latest add https://koten.codehive.com.co/r/date-picker.json

# Bun
bunx shadcn@latest add https://koten.codehive.com.co/r/date-picker.json
```

## Files

- `@/components/ui/date-picker.tsx`
- `@/lib/koten/cn.ts`
- `@/lib/koten/format.ts`
- `@/lib/koten/intl.ts`
- `@/lib/koten/labels.ts`
- `@/lib/koten/provider.tsx`

## Requirements

- **provider** — KotenProvider: useKoten supplies the panel labels and the locale; useKotenFormatters formats the visible value and the calendar days.
- **controlled** — Controlled value (ISO 8601): Store the date as ISO in your state, convert it to Date for value and back to ISO in onValueChange. value and onValueChange are the single source of truth.

## Examples

### Controlled value (ISO)

The application state stores ISO 8601 and the field converts it to Date.

```tsx
const toIso = (date: Date) =>
  `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;

const [iso, setIso] = useState("2026-10-21");
const value = iso ? new Date(`${iso}T00:00:00`) : null;

<DatePicker
  label="Fecha de entrega"
  description="Abre con Enter, Space o clic; Escape cierra y devuelve el foco."
  placeholder="Selecciona una fecha"
  value={value}
  onValueChange={(next) => setIso(next ? toIso(next) : "")}
  min={new Date(2026, 9, 1)}
  max={new Date(2026, 11, 31)}
  defaultMonth={new Date(2026, 9, 1)}
/>
```

### Range

Start and end in a single field; the panel is anchored to the button.

```tsx
const [range, setRange] = useState<DateRange>({
  start: new Date(2026, 9, 21),
  end: new Date(2026, 9, 27),
});

<DatePicker
  mode="range"
  label="Periodo de campaña"
  description="Primer clic: inicio. Segundo clic: fin."
  placeholder="Selecciona un periodo"
  value={range}
  onValueChange={setRange}
  min={new Date(2026, 9, 1)}
  max={new Date(2026, 11, 31)}
  defaultMonth={new Date(2026, 9, 1)}
/>
```

## Props

| Prop | Type | Default | Notes |
| --- | --- | --- | --- |
| `mode` | `"single" \| "range"` | `"single"` | In range mode, value is a DateRange and the panel expects two clicks. |
| `value` | `Date \| DateRange \| null` | `—` | Controlled value; Date in single mode and { start, end } in range mode. |
| `defaultValue` | `Date \| DateRange \| null` | `null` | Initial uncontrolled value. |
| `onValueChange` | `(value: Date \| DateRange \| null) => void` | `—` | Receives Date or DateRange depending on mode; the app usually stores ISO. |
| `label` | `ReactNode` | `—` | Visible label; it also names the panel when dialogLabel is not set. |
| `description` | `ReactNode` | `—` | Help text connected through aria-describedby. |
| `error` | `ReactNode` | `—` | Sets aria-invalid and is announced in an aria-live region. |
| `required` | `boolean` | `false` | Adds the visual asterisk and the field's required state. |
| `disabled` | `boolean` | `false` | Disables the button and prevents the panel from opening. |
| `placeholder` | `string` | `—` | Text when there is no value; shown in the faint color. |
| `min / max` | `Date` | `—` | Days outside the range are disabled. |
| `defaultMonth` | `Date` | `valor u hoy` | Month the panel opens on; defaults to the value or today. |
| `dialogLabel` | `string` | `label` | Accessible name of the panel; defaults to label when it is a string. |
| `className` | `string` | `—` | Classes for the field container. |

## Accessibility

- The field is a button with aria-haspopup="dialog", aria-expanded and aria-controls pointing to the panel.
- The panel is anchored to the field (no portal); Escape closes it and returns focus to the button.
- label, description and error are connected through aria-labelledby and aria-describedby; the error uses aria-live.
- The visible value is formatted with Intl; the controlled state keeps ISO in the application.

## Sources

- Catalog page: https://koten.codehive.com.co/components/date-picker
- Markdown: https://koten.codehive.com.co/md/components/date-picker.md
- Repository: https://github.com/codehive-colombia/koten
