Date picker
BetaUn campo de fecha que se escribe o se elige en un calendario. Incluye el Calendar suelto, con selección de rango.
registry/ds/date-picker.tsxComo figura en tu DNI.
import { DatePicker } from "@/registry/ds/date-picker";
export default function DatePickerBasic() {
return (
<div className="w-72">
<DatePicker label="Fecha de nacimiento" hint="Como figura en tu DNI." max={new Date()} />
</div>
);
}Cuándo usarlo
| Situación | Usá |
|---|---|
| Una fecha que la persona conoce (nacimiento, vencimiento) | Date picker, y dejá que la escriba: el calendario es el atajo. |
| Una fecha que hay que buscar (un turno, un día hábil) | Date picker con min, max e isDateDisabled: el calendario muestra qué se puede. |
| Un período (viaje, examen, filtro) | Calendar en modo range. |
| Solo mes o solo año | Un Select por cada parte. |
Estados y límites
Solo días hábiles entre marzo y junio.
Tiene que ser posterior al inicio.
"use client";
import { DatePicker } from "@/registry/ds/date-picker";
const weekend = (d: Date) => d.getDay() === 0 || d.getDay() === 6;
export default function DatePickerStates() {
return (
<div className="grid w-full max-w-xl gap-5 sm:grid-cols-2">
<DatePicker label="Inicio de cursada" defaultValue={new Date(2026, 2, 9)} min={new Date(2026, 2, 1)} max={new Date(2026, 5, 30)} isDateDisabled={weekend} hint="Solo días hábiles entre marzo y junio." />
<DatePicker label="Con error" defaultValue={new Date(2026, 3, 10)} error="Tiene que ser posterior al inicio." />
<DatePicker label="Deshabilitado" defaultValue={new Date(2026, 0, 15)} disabled />
<DatePicker size="sm" label="Compacto" />
</div>
);
}- Escribir siempre funciona:
dd/mm/aaaa, con/,-o.. Una fecha imposible (31/02) da error al salir del campo. min/maxacotan el calendario y deshabilitan lo de afuera; la ayuda dice el rango en palabras.- El calendario abre en el mes de la fecha elegida, o en el actual.
Calendar y rangos
octubre de 2026
| lun | mar | mié | jue | vie | sáb | dom |
|---|---|---|---|---|---|---|
06/10/2026 → 10/10/2026
"use client";
import { useState } from "react";
import { Calendar, type CalendarRange } from "@/registry/ds/calendar";
import { formatDate } from "@/registry/ds/date-picker";
export default function CalendarRangeExample() {
const [range, setRange] = useState<CalendarRange>({ from: new Date(2026, 9, 6), to: new Date(2026, 9, 10) });
return (
<div className="flex flex-col items-center gap-4">
<Calendar mode="range" value={range} onChange={setRange} aria-label="Período de examen" />
<p className="text-sm text-fg-muted" aria-live="polite">
{range.from ? formatDate(range.from) : "—"} → {range.to ? formatDate(range.to) : "…"}
</p>
</div>
);
}El primer clic marca el inicio; el segundo, el fin (si es anterior, se intercambian). Mientras se elige el fin, el rango sigue al mouse.
Medidas
El campo mide igual que Input; el botón del calendario, 32 / 40 / 48 de ancho, separado por una línea.
| Parte | Medida |
|---|---|
| Popover | padding 12 · radius-lg · Elevation/lg · a 6 del campo |
| Calendario | ancho 288 · celda 36 × 36 · radius-md |
| Navegación de mes | botones 32 · título Text sm / Medium |
| Días de la semana | Text xs / Medium |
| Día | Text sm, tabular |
Tokens
| Parte | Propiedad | Token |
|---|---|---|
| Día | Texto → hover | text/default |
| Día · hover | Fondo | bg/subtle |
| Día fuera del mes | Texto | text/subtle |
| Hoy | Borde interior 1 px | border/strong |
| Elegido / extremos del rango | Fondo | primary/solid |
| Elegido | Texto | primary/on-solid |
| Dentro del rango | Fondo | primary/subtle |
| Dentro del rango | Texto | primary/text |
| Deshabilitado | Texto | text/disabled |
| Botón de mes / calendario | Icono → hover | icon/muted |
| Foco | Anillo interior 2 px | focus/ring |
Instalación
npx shadcn@latest add https://polen.cdc.cool/r/date-picker.jsonTrae también calendar. Para el calendario solo: <Install name="calendar" />.
Playground
Configurá el componente y copiá el snippet: se genera del mismo estado que renderiza el preview.
Como figura en tu documento.
size
<DatePicker label="Fecha de nacimiento" hint="Como figura en tu documento." />Uso
<DatePicker label="Inicio" value={date} onChange={setDate} min={new Date()} />
<Calendar mode="range" value={range} onChange={setRange} />Props de DatePicker
| Prop | Tipo | Default | Descripción |
|---|---|---|---|
value / defaultValue | Date | null | — | Controlado o inicial. |
onChange | (date: Date | null) => void | — | Al elegir, al escribir una fecha válida o al vaciar. |
min · max | Date | — | Límites inclusivos. |
isDateDisabled | (date: Date) => boolean | — | Deshabilita fechas puntuales (fines de semana, feriados). |
placeholder | string | "dd/mm/aaaa" | Formato esperado. |
size · label · hint · error · required · disabled · name | — | — | Como en Input. |
Props de Calendar
| Prop | Tipo | Default | Descripción |
|---|---|---|---|
mode | "single" | "range" | "single" | Una fecha o un período. |
value / onChange | Date | null · { from, to } | — | Según el modo. |
min · max · isDateDisabled | — | — | Como en DatePicker. |
defaultMonth | Date | — | Mes inicial sin valor. |
locale | string | "es-AR" | Nombres de mes y día; la semana empieza en lunes. |
aria-label | string | — | Nombre de la grilla si hay varios calendarios. |
También se exportan formatDate y parseDate (dd/mm/aaaa).
| Tecla | Qué hace |
|---|---|
| Alt↓ | Desde el campo, abre el calendario. |
| Tab | Dentro del calendario: mes anterior → mes siguiente → el día enfocado (una sola parada). |
| ←→↑↓ | Día anterior / siguiente / semana arriba / abajo. Cambia de mes si hace falta. |
| HomeEnd | Lunes / domingo de la semana. |
| PageUpPageDown | Mismo día del mes anterior / siguiente. Con Shift, del año. |
| EnterEspacio | Elige el día enfocado. |
| Esc | Cierra y devuelve el foco al campo. |
- La grilla es una tabla con
role="grid", nombrada por el mes, con los días de la semana como encabezados de columna. - Cada día es un botón con la fecha completa como nombre ("martes, 14 de
octubre de 2026"); hoy lleva
aria-current="date"; los elegidos,aria-selected. Los deshabilitados llevanaria-disabled: se pueden recorrer con las flechas (no bloquean el teclado) pero no se eligen. - El título del mes es una región
aria-live: al navegar se anuncia el mes. - Escribir la fecha es siempre posible: el calendario es un atajo, no la única vía.