Date Picker
Composto de Popover + Calendar - o input de data canônico e pronto para uso distribuído pelo registry do Gremorie.
Visão geral
DatePicker não é um novo primitive; é a composição canônica de Popover + Calendar que o registry expõe como um wrapper pronto para uso. Use para forms compactos onde você quer um input de data que abre um grid de calendário ao clicar.
Modo único por padrão. Para intervalos, use <DatePickerRange /> (item de registry separado). Para UX mobile, prefira Drawer + Calendar - popovers não se comportam bem em telas pequenas.
DatePicker vive em @gremorie/rx-overlays porque compõe um Popover (overlays) com um Calendar (forms). A cadeia de dependência corre overlays -> forms, então o wrapper tem que ficar do lado dos overlays.
Preview
'use client';import { DatePicker } from '@gremorie/rx-overlays';import { useState } from 'react';export function DatePickerPreview() { const [date, setDate] = useState<Date | undefined>(undefined); return ( <DatePicker value={date} onValueChange={setDate} placeholder="Pick a date" /> );}Anatomia
DatePicker composite of Popover + Calendar with Gremorie defaults
├─ Popover floating-surface root
│ ├─ PopoverTrigger asChild wrapper around the outlined Button
│ │ └─ Button outlined trigger (formatted date or placeholder)
│ └─ PopoverContent floating surface (w-auto p-0)
│ └─ Calendar single-mode date gridInstalação
bash npx gremorie@latest add rx-date-picker bash pnpm dlx gremorie@latest add rx-date-picker
bash yarn dlx gremorie@latest add rx-date-picker
bash bunx --bun gremorie@latest add rx-date-picker
Uso
import { DatePicker } from "@gremorie/rx-overlays";
export function Example() {
const [date, setDate] = React.useState<Date>();
return (
<DatePicker value={date} onValueChange={setDate} placeholder="Pick a date" />
);
}A edição Angular deste componente hoje é distribuída a partir do source (veja o side-by-side no workbench); sua entrada no registry vem a seguir.
API
<DatePicker>
| Prop | Type | Default | Descrição |
|---|---|---|---|
value | Date | - | Data selecionada controlada. |
onValueChange | (date: Date | undefined) => void | - | Dispara quando o usuário escolhe uma data no calendário. |
placeholder | string | "Selecione uma data" | Mostrado no trigger quando value está vazio. |
disabled | boolean | false | Desabilita o trigger. |
className | string | - | Classes no Button do trigger. A largura padrão do trigger é w-[240px]. |
Esta é a composição canônica. Se você precisa de comportamento diferente (múltiplo, intervalo, trigger customizado, formato diferente), monte seu próprio Popover + Calendar - este wrapper intencionalmente permanece estreito.
Internamente:
<PopoverTrigger asChild>+<Button variant="outline">- o triggerformat(value, "PP")dodate-fns- o valor formatado ("Apr 29, 2026")<PopoverContent align="start" className="w-auto p-0">- a superfície flutuante<Calendar mode="single" selected={value} onSelect={onValueChange} autoFocus />- o picker
Composição
<DatePicker>é o padrão compacto canônico.- Quando você o supera, monte seu próprio
Popover+Calendar(veja o snippet abaixo) - é o que oDatePickerfaz internamente e é o ponto de partida padrão para variantes. - Para mobile, troque
PopoverporDrawerpara que o calendário ocupe o bottom sheet inteiro em vez de um popover minúsculo acima do teclado.
Variações
Data única controlada (padrão)
function ScheduledFor() {
const [date, setDate] = React.useState<Date>();
return (
<div className="grid gap-2">
<Label htmlFor="scheduled-for">Scheduled for</Label>
<DatePicker
value={date}
onValueChange={setDate}
placeholder="Pick a date"
/>
</div>
);
}Trigger customizado (monte o seu)
Quando você precisa de um trigger diferente - texto inline, uma tag, um botão de ícone - pule o wrapper e componha diretamente. É o que o DatePicker faz internamente.
import { format } from 'date-fns';
import { CalendarIcon } from 'lucide-react';
import { Button, Calendar } from '@gremorie/rx-forms';
import { Popover, PopoverContent, PopoverTrigger } from '@gremorie/rx-overlays';
function CustomTriggerDatePicker() {
const [date, setDate] = React.useState<Date>();
return (
<Popover>
<PopoverTrigger asChild>
<Button variant="ghost" size="sm">
<CalendarIcon />
{date ? format(date, 'PP') : 'Pick a date'}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar mode="single" selected={date} onSelect={setDate} autoFocus />
</PopoverContent>
</Popover>
);
}Intervalo de datas (monte o seu)
Para seletores de intervalo, construa a composição com mode="range" e numberOfMonths={2}.
import type { DateRange } from 'react-day-picker';
function DateRangePicker() {
const [range, setRange] = React.useState<DateRange>();
return (
<Popover>
<PopoverTrigger asChild>
<Button variant="outline" className="w-[280px] justify-start">
<CalendarIcon className="mr-2 size-4" />
{range?.from && range?.to
? `${format(range.from, 'PP')} - ${format(range.to, 'PP')}`
: 'Pick a range'}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
mode="range"
selected={range}
onSelect={setRange}
numberOfMonths={2}
autoFocus
/>
</PopoverContent>
</Popover>
);
}Acessibilidade
- Herda o comportamento do
Popover:Escfecha o popover; o foco retorna ao trigger ao fechar. autoFocusno Calendar: foca a célula ativa (ou a de hoje) assim que o popover abre.- Teclado do Calendar: navegação completa de grid via setas,
Home,End,PageUp,PageDown. Veja acessibilidade do Calendar para a lista completa. - Label do trigger: forneça um
<Label>ligado ao trigger via o wrapper de campo (ex.<FormItem>) para que o date picker tenha um nome acessível. - Disabled: o trigger exibe
disabledpara que o botão se remova da ordem de tab e esmaeça para 50% de opacidade.