Components
- Accordion
- Alert
- Alert Dialog
- Autocomplete
- Avatar
- Badge
- Breadcrumb
- Button
- CalendarNew
- Card
- Checkbox
- Checkbox Group
- Collapsible
- Combobox
- Command
- Date PickerNew
- Dialog
- Empty
- Field
- Fieldset
- Form
- Frame
- Group
- Input
- Input Group
- Kbd
- Label
- Menu
- Meter
- Number Field
- Pagination
- Popover
- Preview Card
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Skeleton
- Slider
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Toolbar
- Tooltip
Resources
Date Picker
A date picker component built with Calendar and Popover.
"use client";
import { format } from "date-fns";
import { CalendarIcon } from "lucide-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
Popover,
PopoverPopup,
PopoverTrigger,
} from "@/components/ui/popover";
export default function Particle() {
const [date, setDate] = useState<Date | undefined>();
return (
<Popover>
<PopoverTrigger
render={<Button className="w-full justify-start" variant="outline" />}
>
<CalendarIcon aria-hidden="true" />
{date ? format(date, "PPP") : "Pick a date"}
</PopoverTrigger>
<PopoverPopup>
<Calendar
defaultMonth={date}
mode="single"
onSelect={setDate}
selected={date}
/>
</PopoverPopup>
</Popover>
);
}
About
The Date Picker is built using a composition of the <Calendar> and <Popover> components.
Installation
The Date Picker is a composition pattern, not a standalone component. Install the required components:
pnpm dlx shadcn@latest add @coss/calendar @coss/popover @coss/button
Usage
import { format } from "date-fns"
import { CalendarIcon } from "lucide-react"
import { useState } from "react"
import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import {
Popover,
PopoverPopup,
PopoverTrigger,
} from "@/components/ui/popover"const [date, setDate] = useState<Date>()
return (
<Popover>
<PopoverTrigger
render={
<Button
className="w-[280px] justify-start text-left font-normal"
variant="outline"
/>
}
>
<CalendarIcon />
{date ? format(date, "PPP") : <span>Pick a date</span>}
</PopoverTrigger>
<PopoverPopup align="start" className="w-auto p-0">
<Calendar mode="single" selected={date} onSelect={setDate} />
</PopoverPopup>
</Popover>
)Examples
Date Range Picker
"use client";
import { format } from "date-fns";
import { CalendarIcon } from "lucide-react";
import { useState } from "react";
import type { DateRange } from "react-day-picker";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
Popover,
PopoverPopup,
PopoverTrigger,
} from "@/components/ui/popover";
export default function Particle() {
const [date, setDate] = useState<DateRange | undefined>();
return (
<Popover>
<PopoverTrigger
render={<Button className="w-full justify-start" variant="outline" />}
>
<CalendarIcon aria-hidden="true" />
{date?.from ? (
date.to ? (
<>
{format(date.from, "LLL dd, y")} - {format(date.to, "LLL dd, y")}
</>
) : (
format(date.from, "LLL dd, y")
)
) : (
<span>Pick a date range</span>
)}
</PopoverTrigger>
<PopoverPopup>
<Calendar
defaultMonth={date?.from}
mode="range"
onSelect={setDate}
selected={date}
/>
</PopoverPopup>
</Popover>
);
}
With Dropdown Navigation
Use captionLayout="dropdown" for date of birth or historical date selection:
"use client";
import { format } from "date-fns";
import { CalendarIcon } from "lucide-react";
import * as React from "react";
import type { DropdownProps } from "react-day-picker";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
} from "@/components/ui/combobox";
import { Field, FieldLabel } from "@/components/ui/field";
import {
Popover,
PopoverPopup,
PopoverTrigger,
} from "@/components/ui/popover";
interface DropdownItem {
disabled?: boolean;
label: string;
value: string;
}
function CalendarDropdown(props: DropdownProps) {
const { options, value, onChange, "aria-label": ariaLabel } = props;
const items: DropdownItem[] =
options?.map((option) => ({
disabled: option.disabled,
label: option.label,
value: option.value.toString(),
})) ?? [];
const selectedItem = items.find((item) => item.value === value?.toString());
const handleValueChange = (newValue: DropdownItem | null) => {
if (onChange && newValue) {
const syntheticEvent = {
target: { value: newValue.value },
} as React.ChangeEvent<HTMLSelectElement>;
onChange(syntheticEvent);
}
};
return (
<Combobox
aria-label={ariaLabel}
autoHighlight
items={items}
onValueChange={handleValueChange}
value={selectedItem}
>
<ComboboxInput
className="**:[input]:w-0 **:[input]:flex-1"
onFocus={(e) => e.currentTarget.select()}
/>
<ComboboxPopup aria-label={ariaLabel}>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item: DropdownItem) => (
<ComboboxItem
disabled={item.disabled}
key={item.value}
value={item}
>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
);
}
export default function Particle() {
const [date, setDate] = React.useState<Date | undefined>();
const id = React.useId();
return (
<Field>
<FieldLabel htmlFor={id}>Start date</FieldLabel>
<Popover>
<PopoverTrigger
id={id}
render={<Button className="w-full justify-start" variant="outline" />}
>
<CalendarIcon aria-hidden="true" />
{date ? format(date, "PPP") : "Pick a date"}
</PopoverTrigger>
<PopoverPopup>
<Calendar
captionLayout="dropdown"
components={{ Dropdown: CalendarDropdown }}
defaultMonth={date}
endMonth={new Date()}
mode="single"
onSelect={setDate}
selected={date}
startMonth={new Date(1900, 0)}
/>
</PopoverPopup>
</Popover>
</Field>
);
}
With Presets
"use client";
import { addDays, format } from "date-fns";
import { CalendarIcon } from "lucide-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
Popover,
PopoverPopup,
PopoverTrigger,
} from "@/components/ui/popover";
export default function Particle() {
const today = new Date();
const [month, setMonth] = useState(today);
const [date, setDate] = useState<Date | undefined>(today);
return (
<Popover>
<PopoverTrigger
render={<Button className="w-full justify-start" variant="outline" />}
>
<CalendarIcon aria-hidden="true" />
{date ? format(date, "PPP") : "Pick a date"}
</PopoverTrigger>
<PopoverPopup>
<div className="flex max-sm:flex-col">
<div className="relative py-1 ps-1 max-sm:order-1 max-sm:border-t">
<div className="flex h-full flex-col sm:border-e sm:pe-3">
<Button
className="w-full justify-start"
onClick={() => {
setDate(today);
setMonth(today);
}}
size="sm"
variant="ghost"
>
Today
</Button>
<Button
className="w-full justify-start"
onClick={() => {
const tomorrow = addDays(today, 1);
setDate(tomorrow);
setMonth(tomorrow);
}}
size="sm"
variant="ghost"
>
Tomorrow
</Button>
<Button
className="w-full justify-start"
onClick={() => {
const in3Days = addDays(today, 3);
setDate(in3Days);
setMonth(in3Days);
}}
size="sm"
variant="ghost"
>
In 3 days
</Button>
<Button
className="w-full justify-start"
onClick={() => {
const inAWeek = addDays(today, 7);
setDate(inAWeek);
setMonth(inAWeek);
}}
size="sm"
variant="ghost"
>
In a week
</Button>
</div>
</div>
<Calendar
className="max-sm:pb-3 sm:ps-2"
mode="single"
month={month}
onMonthChange={setMonth}
onSelect={setDate}
selected={date}
/>
</div>
</PopoverPopup>
</Popover>
);
}
With Input
"use client";
import { format, isValid, parse } from "date-fns";
import { CalendarIcon } from "lucide-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
InputGroup,
InputGroupAddon,
InputGroupInput,
} from "@/components/ui/input-group";
import {
Popover,
PopoverPopup,
PopoverTrigger,
} from "@/components/ui/popover";
export default function Particle() {
const [date, setDate] = useState<Date | undefined>();
const [inputValue, setInputValue] = useState("");
const [month, setMonth] = useState<Date>(() => new Date());
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
setInputValue(value);
if (value) {
const parsedDate = parse(value, "yyyy-MM-dd", new Date());
if (isValid(parsedDate)) {
setDate(parsedDate);
setMonth(parsedDate);
}
} else {
setDate(undefined);
}
};
const handleSelect = (selectedDate: Date | undefined) => {
setDate(selectedDate);
if (selectedDate) {
setInputValue(format(selectedDate, "yyyy-MM-dd"));
setMonth(selectedDate);
} else {
setInputValue("");
}
};
return (
<Popover>
<InputGroup>
<InputGroupInput
aria-label="Select date"
className="*:[input]:[&::-webkit-calendar-picker-indicator]:hidden *:[input]:[&::-webkit-calendar-picker-indicator]:appearance-none"
onChange={handleInputChange}
onClick={(e) => e.stopPropagation()}
type="date"
value={inputValue}
/>
<InputGroupAddon>
<PopoverTrigger
aria-label="Select date"
render={
<Button aria-label="Select date" size="icon-xs" variant="ghost" />
}
>
<CalendarIcon aria-hidden="true" />
</PopoverTrigger>
</InputGroupAddon>
</InputGroup>
<PopoverPopup align="start" alignOffset={-4} sideOffset={8}>
<Calendar
mode="single"
month={month}
onMonthChange={setMonth}
onSelect={handleSelect}
selected={date}
/>
</PopoverPopup>
</Popover>
);
}
Close on Select
Control the popover state to close it when a date is selected:
"use client";
import { format } from "date-fns";
import { CalendarIcon } from "lucide-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
Popover,
PopoverPopup,
PopoverTrigger,
} from "@/components/ui/popover";
export default function Particle() {
const [date, setDate] = useState<Date | undefined>();
const [open, setOpen] = useState(false);
const handleSelect = (selectedDate: Date | undefined) => {
setDate(selectedDate);
setOpen(false);
};
return (
<Popover onOpenChange={setOpen} open={open}>
<PopoverTrigger
render={<Button className="w-full justify-start" variant="outline" />}
>
<CalendarIcon />
{date ? format(date, "PPP") : "Pick a date"}
</PopoverTrigger>
<PopoverPopup>
<Calendar mode="single" onSelect={handleSelect} selected={date} />
</PopoverPopup>
</Popover>
);
}