Ir al contenido
Formularios

DatePicker

Un campo que abre un calendario. Reemplaza a <input type="date">, cuyo calendario es del navegador y no se puede estilar.

import { DatePicker } from "sebs7n-ui/date-picker"

Ejemplos

Básico

El campo es un botón: el `<Label htmlFor>` lo nombra y, al hacerle clic, abre el calendario.

import { DatePicker } from "sebs7n-ui/date-picker"
import { Label } from "sebs7n-ui/label"
import { useId } from "react"

function Basico() {
  const id = useId()
  return (
    <div className="flex w-full max-w-xs flex-col gap-2">
      <Label htmlFor={id}>Vencimiento</Label>
      <DatePicker defaultValue={new Date(2026, 8, 27)} id={id} name="vencimiento" />
    </div>
  )
}

Un rango

Se queda abierto después del desde y se cierra con el hasta.

import { DatePicker } from "sebs7n-ui/date-picker"
import { DateRange } from "sebs7n-ui/lib/dates"
import { Label } from "sebs7n-ui/label"
import { useId, useState } from "react"

function Rango() {
  const id = useId()
  const [periodo, setPeriodo] = useState<DateRange>({ from: null, to: null })
  return (
    <div className="flex w-full max-w-xs flex-col gap-2">
      <Label htmlFor={id}>Período</Label>
      <DatePicker id={id} mode="range" onValueChange={setPeriodo} value={periodo} />
    </div>
  )
}

Con Limpiar

`clearable` suma un pie para vaciar la fecha: un filtro o un campo opcional no puede ser un camino sin vuelta.

import { DatePicker } from "sebs7n-ui/date-picker"
import { Label } from "sebs7n-ui/label"
import { useId } from "react"

function ConLimpiar() {
  const id = useId()
  return (
    <div className="flex w-full max-w-xs flex-col gap-2">
      <Label htmlFor={id}>Facturas desde</Label>
      <DatePicker clearable defaultValue={new Date(2026, 8, 1)} id={id} name="desde" />
    </div>
  )
}

Tamaños, formato y límites

Las mismas tres alturas que `Input`. `format` es el de `Intl.DateTimeFormat`.

import { DatePicker } from "sebs7n-ui/date-picker"

function TamanosYFormato() {
  return (
    <div className="flex w-full max-w-xs flex-col gap-3">
      <DatePicker aria-label="Fecha corta" defaultValue={new Date(2026, 8, 27)} format={{ dateStyle: "short" }} size="sm" />
      <DatePicker aria-label="Fecha larga" defaultValue={new Date(2026, 8, 27)} format={{ dateStyle: "long" }} />
      <DatePicker aria-label="Turno" max={new Date(2026, 9, 16)} min={new Date(2026, 8, 7)} size="lg" />
      <DatePicker aria-label="Sin turnos" disabled />
    </div>
  )
}

Una fecha lejana

En el calendario, el título abre la grilla de meses y su año la de años. Escape vuelve a los días sin cerrar el panel.

import { DatePicker } from "sebs7n-ui/date-picker"
import { Label } from "sebs7n-ui/label"
import { useId } from "react"

function FechaDeAlta() {
  const id = useId()
  return (
    <div className="flex w-full max-w-xs flex-col gap-2">
      <Label htmlFor={id}>Fecha de alta del cliente</Label>
      <DatePicker defaultValue={new Date(2006, 3, 12)} id={id} max={new Date(2026, 8, 29)} name="alta" />
    </div>
  )
}

Idioma global

`LabelsProvider` con `dates`: idioma, semana y formato para `DatePicker`, `DateTimePicker` y `Calendar` de abajo (y `CalendarView`). La prop de cada uno le gana.

import { Calendar } from "sebs7n-ui/calendar"
import { DatePicker } from "sebs7n-ui/date-picker"
import { DateTimePicker } from "sebs7n-ui/date-time-picker"
import { Label } from "sebs7n-ui/label"
import { LabelsProvider } from "sebs7n-ui/labels"
import { useState } from "react"

function IdiomaGlobal() {
  const [due, setDue] = useState<Date | null>(new Date(2026, 9, 15))
  return (
    <LabelsProvider value={{ dates: { locale: "en-US", weekStartsOn: 0, format: NUMERIC } }}>
      <div className="flex flex-col gap-4">
        <div className="flex flex-col gap-1.5">
          <Label htmlFor="due-global">Due date</Label>
          <DatePicker className="w-56" id="due-global" onValueChange={setDue} value={due} />
        </div>
        <DateTimePicker aria-label="Issued at" className="w-72" defaultValue={new Date(2026, 9, 1, 9, 30)} />
        <Calendar className="self-start" defaultMonth={new Date(2026, 9, 1)} />
      </div>
    </LabelsProvider>
  )
}

En un Field

`FieldLabel`, ayuda y error se enganchan solos; con `required`, sin fecha u hora `Form` no envía y enfoca el campo.

import { Button } from "sebs7n-ui/button"
import { DatePicker } from "sebs7n-ui/date-picker"
import { Field, FieldDescription, FieldError, FieldLabel } from "sebs7n-ui/field"
import { Form } from "sebs7n-ui/form"
import { TimePicker } from "sebs7n-ui/time-picker"
import { useState } from "react"

function EnField() {
  const [sent, setSent] = useState<string | null>(null)
  return (
    <Form className="flex w-full max-w-sm flex-col gap-4" onFormSubmit={(values) => setSent(JSON.stringify(values))}>
      <Field name="due">
        <FieldLabel>Vencimiento</FieldLabel>
        <DatePicker required />
        <FieldDescription>El día que vence la factura.</FieldDescription>
        <FieldError>Elegí una fecha.</FieldError>
      </Field>
      <Field name="sendAt">
        <FieldLabel>Hora de envío</FieldLabel>
        <TimePicker required />
        <FieldError>Elegí una hora.</FieldError>
      </Field>
      <Button className="self-start" type="submit">
        Programar
      </Button>
      {sent && <p className="text-footnote text-label-secondary">{sent}</p>}
    </Form>
  )
}

Props

Generadas del TypeScript del paquete. Las propias del componente, más las heredadas del primitivo que tienen algo que explicar —marcadas «heredada de Base UI»—. El resto está en la línea «hereda de».

DatePicker

PropTipoPor defectoDescripción
clearableboolean—Suma un «Limpiar» al pie del calendario cuando hay fecha elegida: para un filtro o un campo opcional, donde elegir una fecha no puede ser un camino sin vuelta.
defaultValueDate | DateRange—La fecha elegida al montar, sin controlar.
formatIntl.DateTimeFormatOptions—Cómo se escribe la fecha en el campo. Por defecto, { dateStyle: "medium" }: «27 sept 2026».
isDateDisabled(date: Date) => boolean—Apaga fechas sueltas: feriados, fines de semana, días sin turno.
labelsPartial<DatePickerLabels & Labels["calendar"]>—El texto del campo vacío y los nombres de los botones del calendario.
localestring—El idioma de la fecha y del calendario, como lo entiende Intl. Por defecto, es-AR.
maxDate—La última fecha que se puede elegir.
minDate—La primera fecha que se puede elegir.
mode"single" | "range"—single elige una fecha; range, un desde y un hasta.
namestring—El nombre con el que la fecha viaja en un formulario, como 2026-09-27. En range salen dos campos: nombre-desde y nombre-hasta.
numberOfMonthsnumber—Cuántos meses muestra el calendario, uno al lado del otro. Por defecto, 1.
onOpenChange(open: boolean) => void—Avisa cuando se abre o se cierra.
onValueChange((value: Date | null) => void) | ((value: DateRange) => void)—Avisa la fecha elegida.
openboolean—El calendario abierto o cerrado, controlado.
popupClassNamestring—Clases del panel del calendario.
requiredboolean—Sin fecha no se puede enviar: dentro de un Form, el campo queda inválido y Form lo enfoca. En range, hacen falta las dos puntas.
size"sm" | "md" | "lg"—Las mismas tres alturas que Input, para que un formulario mixto quede alineado.
valueDate | DateRange—La fecha elegida, controlada. null es ninguna.
weekStartsOn0 | 1—Con qué día arranca la semana: 1 lunes (el default), 0 domingo.
disabledboolean—Heredada de Base UI. Apaga la interacción y lo marca con data-disabled, que es el atributo del que cuelgan los estilos de apagado.
classNamestring—Heredada de Base UI. Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana.

Teclado

Enter · Espacio
Abre el calendario, con el foco en la fecha elegida.
Escape
Cierra y devuelve el foco al campo.
← → ↑ ↓
Se mueve por los días. Ver Calendar.
Escape (meses y años)
Vuelve a los días; el segundo Escape cierra.

Accesibilidad

  • El campo es un botón: necesita aria-label, aria-labelledby o un <Label htmlFor> apuntando a su id.
  • La fecha se escribe con Intl en el idioma que se le pasa (locale), no en el del navegador.
  • Dentro de un Field se registra como su control: FieldLabel lo nombra junto con la fecha («Vencimiento 27 sept 2026»), FieldDescription y FieldError lo describen y Form lo enfoca si queda inválido al enviar.

Reglas de uso

  • En una pantalla angosta (< 640 px) el calendario se abre en la hoja de abajo, como el Popover: a todo el ancho, arrastrable y con la X. Con numberOfMonths={2} los meses se apilan.
  • Idioma y semana para toda la app: <LabelsProvider value={{ dates: { locale: "en-US", weekStartsOn: 0 } }}> (también format para el campo de DatePicker). Lo leen Calendar, DatePicker, DateTimePicker y CalendarView; la prop de cada uno gana.
  • Para fechas que se eligen mirando un calendario: un turno, un vencimiento cercano, un período.
  • Una fecha lejana no se recorre mes por mes: el título del calendario abre la grilla de meses, y su año la de años. Si lo normal es tipearla —un vencimiento que se copia de un papel—, va un Input.
  • mode="range" elige desde y hasta en el mismo calendario, y se cierra recién con el segundo clic.
  • Con name (o el name del Field), la fecha viaja en el formulario como 2026-09-27. En rango salen dos campos: nombre-desde y nombre-hasta. En onFormSubmit de Form llega el ISO (en rango, { from, to }).
  • required: sin fecha (en rango, sin las dos puntas) Form no envía, marca el campo inválido y lo enfoca.
  • Con clearable, el pie del calendario ofrece «Limpiar» cuando hay fecha: para filtros y campos opcionales.

Relacionados