Components
- AccordionNew
- Alert
- Alert DialogNew
- AutocompleteNew
- AvatarNew
- Badge
- Breadcrumb
- Button
- CalendarNew
- CardNew
- Checkbox
- Checkbox GroupNew
- CollapsibleNew
- ComboboxNew
- CommandNew
- Context MenuNew
- Date PickerNew
- DialogNew
- DrawerNew
- EmptyNew
- FieldNew
- FieldsetNew
- FormNew
- FrameNew
- GroupNew
- Input
- Input GroupNew
- KbdNew
- Label
- MenuNew
- MeterNew
- Number Field
- OTP FieldNew
- Pagination
- PopoverNew
- Preview CardNew
- Progress
- Radio Group
- Scroll AreaNew
- Select
- Separator
- SheetNew
- SkeletonNew
- Slider
- Spinner
- StepperNew
- Switch
- Table
- TabsNew
- Textarea
- ToastNew
- ToggleNew
- Toggle GroupNew
- ToolbarNew
- Tooltip
Date Picker
A date picker component built with Calendar and Popover.
"use client";
import { format } from "date-fns";
import { Button } from "mako-ui/components/button";
import { Calendar } from "mako-ui/components/calendar";
import {
Popover,
PopoverPopup,
PopoverTrigger,
} from "mako-ui/components/popover";
import { Date as DateIcon } from "mako-ui/icons/date";
import { useState } from "react";
export default function Particle() {
const [date, setDate] = useState<Date | undefined>();
return (
<Popover>
<PopoverTrigger
render={<Button className="w-full justify-start" variant="outline" />}
>
<DateIcon 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.
Usage
import { format } from "date-fns"
import { Date as DateIcon } from "mako-ui/icons/date";
import { useState } from "react"
import { Button } from "mako-ui/components/button"
import { Calendar } from "mako-ui/components/calendar"
import {
Popover,
PopoverPopup,
PopoverTrigger,
} from "mako-ui/components/popover"const [date, setDate] = useState<Date>()
return (
<Popover>
<PopoverTrigger
render={
<Button
className="w-[280px] justify-start text-left font-normal"
variant="outline"
/>
}
>
<DateIcon />
{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 type { DateRange } from "@daypicker/react";
import { format } from "date-fns";
import { Button } from "mako-ui/components/button";
import { Calendar } from "mako-ui/components/calendar";
import {
Popover,
PopoverPopup,
PopoverTrigger,
} from "mako-ui/components/popover";
import { Date as DateIcon } from "mako-ui/icons/date";
import { useState } from "react";
function formatDateRange(from: Date, to?: Date): string {
const start = format(from, "LLL dd, y");
return to ? `${start} - ${format(to, "LLL dd, y")}` : start;
}
export default function Particle() {
const [date, setDate] = useState<DateRange | undefined>();
return (
<Popover>
<PopoverTrigger
render={<Button className="w-full justify-start" variant="outline" />}
>
<DateIcon aria-hidden="true" />
{date?.from ? (
formatDateRange(date.from, date.to)
) : (
<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 type { DropdownProps } from "@daypicker/react";
import { format } from "date-fns";
import { Button } from "mako-ui/components/button";
import { Calendar } from "mako-ui/components/calendar";
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
} from "mako-ui/components/combobox";
import { Field, FieldLabel } from "mako-ui/components/field";
import {
Popover,
PopoverPopup,
PopoverTrigger,
} from "mako-ui/components/popover";
import { Date as DateIcon } from "mako-ui/icons/date";
import * as React from "react";
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" />}
>
<DateIcon 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 { Button } from "mako-ui/components/button";
import { Calendar } from "mako-ui/components/calendar";
import {
Popover,
PopoverPopup,
PopoverTrigger,
} from "mako-ui/components/popover";
import { Date as DateIcon } from "mako-ui/icons/date";
import { useState } from "react";
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" />}
>
<DateIcon 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 { Button } from "mako-ui/components/button";
import { Calendar } from "mako-ui/components/calendar";
import {
InputGroup,
InputGroupAddon,
InputGroupInput,
} from "mako-ui/components/input-group";
import {
Popover,
PopoverPopup,
PopoverTrigger,
} from "mako-ui/components/popover";
import { Date as DateIcon } from "mako-ui/icons/date";
import { useState } from "react";
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" />
}
>
<DateIcon 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 { Button } from "mako-ui/components/button";
import { Calendar } from "mako-ui/components/calendar";
import {
Popover,
PopoverPopup,
PopoverTrigger,
} from "mako-ui/components/popover";
import { Date as DateIcon } from "mako-ui/icons/date";
import { useState } from "react";
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" />}
>
<DateIcon />
{date ? format(date, "PPP") : "Pick a date"}
</PopoverTrigger>
<PopoverPopup>
<Calendar mode="single" onSelect={handleSelect} selected={date} />
</PopoverPopup>
</Popover>
);
}