A fully customizable Monthpicker
and Monthrangepicker
component built for shadcn-ui.
(Radix, Tailwind CSS).
The components require the following shadcn-ui components.
CLI Installation:
npx shadcn-ui@latest add button popover
Link to components:
Also Lucide React is requiered for the Icons.
import React from "react";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Button } from "@/components/ui/button";
import { CalendarIcon } from "lucide-react";
import { format } from "date-fns/format";
import { cn } from "@/lib/utils";
import { MonthPicker } from "@/components/ui/monthpicker";
export default function Example() {
const [date, setDate] = React.useState<Date>();
return <MonthPicker onMonthSelect={setDate} selectedDate={date} />;
}
Use with shadcn-ui Popover
component:
export default function Example() {
const [date, setDate] = React.useState<Date>();
return (
<Popover>
<PopoverTrigger asChild>
<Button variant={"outline"} className={cn("w-[280px] justify-start text-left font-normal", !date && "text-muted-foreground")}>
<CalendarIcon className="mr-2 h-4 w-4" />
{date ? format(date, "MMM yyyy") : <span>Pick a month</span>}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<MonthPicker onMonthSelect={setDate} selectedMonth={date} />
</PopoverContent>
</Popover>
);
}
Prop | Type | Default | Description |
---|---|---|---|
onMonthSelect |
(date: Date) => void | - | Called when a month has been selected |
selectedMonth |
Date | Today’s Month | Month state for initialization |
minDate |
Date | no limit | The minimum selectable date |
maxDate |
Date | no limit | The maximum selectable date |
disabledDates |
Date[] | - | Separate non-selectable months |
callbacks |
object | - | See callbacks table |
variant |
object | - | See variant table |
onYearForward |
() => void | - | Called when calendar browsed forward |
onYearBackward |
() => void | - | Called when calendar browsed backward |
callbacks
| Prop | Type | Description | | ------------ | ------------------------ | --------------------------------- | | `yearLabel` | (year: number) => string | Used for styling the Year Label | | `monthLabel` | (month: Month) | Used for styling the Month Labels |type Month = { number: number; name: string };
variant
Prop | Type | Description |
---|---|---|
calendar |
{main: ButtonVariant, selected: ButtonVariant } |
Styling for the Month-buttons. main for non-selected & selected for selected Button |
chevrons |
ButtonVariant | Styling for the backward- & forward-chevron buttons |
type ButtonVariant = "default" | "outline" | "ghost" | "link" | "destructive" | "secondary" | null | undefined;
import React from "react";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Button } from "@/components/ui/button";
import { CalendarIcon } from "lucide-react";
import { format } from "date-fns/format";
import { cn } from "@/lib/utils";
import { MonthRangePicker } from "@/components/ui/monthrangepicker";
export default function Example() {
const [dates, setDates] = React.useState<{ start: Date; end: Date }>();
return <MonthRangePicker onMonthRangeSelect={setDates} selectedMonthRange={dates} />;
}
Use with shadcn-ui Popover
component:
export default function Example() {
const [dates, setDates] = React.useState<{ start: Date; end: Date }>();
return (
<Popover>
<PopoverTrigger asChild>
<Button variant={"outline"} className={cn("w-[280px] justify-start text-left font-normal", !date && "text-muted-foreground")}>
<CalendarIcon className="mr-2 h-4 w-4" />
{dates ? `${format(dates.start, "MMM yyyy")} - ${format(dates.end, "MMM yyyy")}` : <span>Pick a month range</span>}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<MonthRangePicker onMonthRangeSelect={setDates} selectedMonthRange={dates} />
</PopoverContent>
</Popover>
);
}
Prop | Type | Default | Description |
---|---|---|---|
onMonthRangeSelect |
(date: Date) => void | - | Called when a month range has been selected |
onStartMonthSelect |
(date: Date) => void | - | Called when the range start month has been selected and the range end is still pending |
selectedMonthRange |
Date | Today’s Month | Month state for initialization |
minDate |
Date | no limit | The minimum selectable date |
maxDate |
Date | no limit | The maximum selectable date |
callbacks |
object | - | See callbacks table |
variant |
object | - | See variant table |
onYearForward |
() => void | - | Called when calendar browsed forward |
onYearBackward |
() => void | - | Called when calendar browsed backward |
quickSelectors |
Object[] | - | See quickselectors table |
showQuickSelectors |
boolean | true | Show/Hide the quickselectors |
quickselectors
Prop | Type | Description |
---|---|---|
label |
string | Label for the button |
startMonth |
Date | Date for the range start month |
endMonth |
Date | Date for the range end month |
variant |
ButtonVariant | variant for the button |
onClick |
(selector: QuickSelector) => void | Called when quick selection has been clicked |
callbacks
Prop | Type | Description |
---|---|---|
yearLabel |
(year: number) => string | Used for styling the Year Label |
monthLabel |
(month: Month) | Used for styling the Month Labels |
type Month = { number: number; name: string; yearOffset: number }; // yearOffset = 0 on the left calendar and 1 on the right side calendar
variant
Prop | Type | Description |
---|---|---|
calendar |
{main: ButtonVariant, selected: ButtonVariant } |
Styling for the Month-buttons. main for non-selected & selected for selected Button |
chevrons |
ButtonVariant | Styling for the backward- & forward-chevron buttons |
type ButtonVariant = "default" | "outline" | "ghost" | "link" | "destructive" | "secondary" | null | undefined;
You can use Monthpicker and Monthrangepicker with shadcn forms. A Form schema could look like this:
const FormSchema = z.object({
month: z.date(),
monthrange: z.object({
start: z.date(),
end: z.date(),
}),
});
You can check out a full form example here