Calendar
Una cuadrícula de fechas para selección única, de rango y múltiple, con meses deslizantes, vistas previas de rango y días de tamaño táctil.
| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
pnpm dlx shadcn@latest add https://hextaui.com/r/calendar.jsonAñade el componente, los tokens del tema de HextaUI y los componentes de HextaUI de los que depende.
Añade los tokens del tema a tu CSS global, si aún no lo has hecho.
Instala las dependencias.
pnpm add react-day-picker @base-ui/react @tabler/icons-react class-variance-authority cnCopia y pega el siguiente código en tu proyecto.
components/ui/calendar.tsx components/ui/button.tsx lib/motion.ts Actualiza las rutas de importación para que coincidan con la configuración de tu proyecto.
Calendar envuelve el <DayPicker /> de react-day-picker, así que todas las props de DayPicker funcionan tal como se documentan en daypicker.dev. HextaUI añade estilos, transiciones de mes, una vista previa del rango y un today seguro para la hidratación.
Rango
Con mode="range", tras el primer clic, pasar el cursor o dar foco a un día muestra una vista previa del rango que seleccionará el siguiente clic. numberOfMonths muestra los meses uno al lado del otro, apilados en pantallas estrechas.
Límites del rango
min y max limitan la longitud del rango en días. Con excludeDisabled, un rango que incluiría un día deshabilitado se reinicia.
Múltiple
mode="multiple" alterna días individuales. max limita cuántos se pueden seleccionar.
Desplegables de mes y año
captionLayout="dropdown" reemplaza el título por selects nativos, de modo que los teléfonos obtienen su propio selector. Define startMonth y endMonth para acotar los años.
Acotado
La navegación se detiene en startMonth y endMonth, y disabled bloquea los días fuera de la ventana. useToday() te da un today seguro para usar durante el renderizado en el servidor.
Mes controlado
Pasa month y onMonthChange para controlar el mes visible. Los saltos se deslizan en la dirección del recorrido y la altura se ajusta suavemente entre filas de 5 y 6 semanas.
Números de semana
showWeekNumber añade una columna de semana. ISOWeek usa la numeración ISO, que empieza en lunes. showOutsideDays={false} oculta los días de otros meses.
Today fijo
Pasa today para fijar el día resaltado, para pruebas u otra zona horaria. animate={false} desactiva las transiciones de mes.
Dentro de una hoja
Dentro de un sheet, popover o diálogo, el calendario elimina su propio fondo y se funde con la superficie.
De derecha a izquierda
Pasa un locale de react-day-picker/locale y dir="rtl". Las flechas, la navegación y la dirección del deslizamiento se reflejan. Dentro de un DirectionProvider con dir="rtl", la dirección se detecta automáticamente.
Da foco a un día y usa estas teclas. Pasar del mes visible cambia el mes.
| Key | Acción |
|---|---|
| ←→ | Día anterior o siguiente. Invertido en diseños de derecha a izquierda. |
| ↑↓ | El mismo día de la semana anterior o siguiente. |
| Shift←→ | Mes anterior o siguiente. |
| Shift↑↓ | Año anterior o siguiente. |
| Page UpPage Down | Mes anterior o siguiente. |
| ShiftPage UpPage Down | Año anterior o siguiente. |
| Home | Primer día de la semana. |
| End | Último día de la semana. |
| EnterSpace | Selecciona el día con foco. |
- El mes es una cuadrícula. Cada día es un botón con una etiqueta de fecha completa, y los días seleccionados definen
aria-selected. - Los cambios de mes hechos con el teclado omiten el deslizamiento y solo hacen un fundido, para que el foco nunca se mueva bajo una cuadrícula en movimiento.
- Con movimiento reducido, los cambios de mes se desvanecen y el cambio de altura es instantáneo.
- En pantallas táctiles, las celdas de día crecen hasta 44px.
Acepta todas las props de <DayPicker />. Los valores por defecto de abajo difieren de los de DayPicker o los añade HextaUI.
| Prop | Tipo | Predeterminado |
|---|---|---|
modeSin un modo, los días no se pueden seleccionar. | "single" | "multiple" | "range" | – |
selectedCoincide con el modo. | Date | Date[] | DateRange | – |
onSelect | (selected, triggerDate, modifiers, event) => void | – |
requiredImpide deseleccionar la última selección. | boolean | – |
minMínimo de días en un rango, o seleccionados en modo multiple. | number | – |
maxMáximo de días en un rango, o seleccionados en modo multiple. | number | – |
excludeDisabledModo range. | boolean | – |
disabled | Matcher | Matcher[] | – |
monthMes controlado. | Date | – |
defaultMonth | Date | – |
onMonthChange | (month: Date) => void | – |
startMonth | Date | – |
endMonth | Date | – |
numberOfMonths | number | 1 |
captionLayout | "label" | "dropdown" | "dropdown-months" | "dropdown-years" | "label" |
navLayoutValor por defecto de HextaUI. Las flechas van a cada lado del título. | "around" | "after" | "around" |
showOutsideDaysValor por defecto de HextaUI. | boolean | true |
animateTransiciones de deslizamiento de mes y de altura. Valor por defecto de HextaUI. | boolean | true |
buttonVariantVariante de los botones de anterior y siguiente. | Button variant | "ghost" |
showWeekNumber | boolean | false |
ISOWeek | boolean | false |
weekStartsOn | 0 | 1 | 2 | 3 | 4 | 5 | 6 | – |
fixedWeeks | boolean | false |
todayPor defecto es el today del cliente, mantenido sincronizado a través de la medianoche y la hidratación. | Date | – |
timeZone | string | – |
locale | Partial<DayPickerLocale> | – |
dir | "ltr" | "rtl" | – |
footer | ReactNode | – |
| Atributo | Descripción |
|---|---|
data-slot="calendar" | Selecciona la raíz del calendario en CSS. |
--cell-size | Tamaño de la celda de día. 36px, o 44px en pantallas táctiles. |
--cell-radius | Radio de las esquinas de las celdas y botones de día. |
data-slot="calendar-day" | Celdas de día. Llevan data-selected, data-disabled, data-outside, data-today, data-hidden y data-focused. |
data-preview | En las celdas de día: inicio, medio o fin de la vista previa del rango bajo el cursor. |
data-range-middle | En las celdas de día dentro de un rango seleccionado. |
El botón dentro de cada día. Pasa el tuyo a components={{ DayButton }} y reutiliza este para conservar el estilo.
| Atributo | Descripción |
|---|---|
data-slot="calendar-day-button" | Selecciona los botones de día en CSS. |
data-day | La fecha ISO, como 2026-10-03. |
data-today | Presente en today, excluidos los días de fuera del mes. |
data-selected-single | Seleccionado fuera de un rango. |
data-range-start | Primer día del rango. |
data-range-middle | Un día dentro del rango. |
data-range-end | Último día del rango. |
Devuelve today como un Date en el cliente y undefined durante el renderizado en el servidor, así que los límites construidos a partir de él nunca causan una discrepancia de hidratación. Se actualiza a medianoche. Consulta la guía de useToday.
- ButtonBotones en todas las variantes y tamaños, con un flujo integrado de carga, éxito y error que omite el spinner en las peticiones rápidas.
- MotionLas curvas de easing, duraciones y la comprobación de movimiento reducido con las que se anima cada componente, además de hooks para transformaciones de tamaño y resaltados deslizantes.
- useTodayLa fecha de hoy, que se actualiza a medianoche y cuando la pestaña vuelve a primer plano, sin discrepancia de hidratación.
- CheckboxUna casilla de verificación cuya marca se dibuja, con padres indeterminados, grupos y etiquetas que comparten su hover.
- ComboboxUn select filtrable con chips, grupos y resultados asíncronos, en un popup que cambia de tamaño mientras escribes.
- Date pickerUn botón que abre un calendario en un popover, o en una hoja inferior en móviles, para fechas únicas y rangos.