Calendar [React Day Picker] | Community Components | 21st

21st home

Origin UI/Calendar [React Day Picker]/Range calendar with presets

Search K

Pricing Sign in

Calendar [React Day Picker]

Calendar [React Day Picker]

Origin UI](/content/@originui/library/origin-ui/index.html) by Origin UI](/content/@originui/index.html)

Copy prompt

SaveRemixCLIReport

SaveCopy prompt

PreviewCodeInfo

React App

TodayYesterdayLast 7 daysLast 30 daysMonth to dateLast monthYear to dateLast year

August 2026

Su Mo Tu We Th Fr Sa
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

Range calendar with presets - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
  endOfMonth,
  endOfYear,
  startOfMonth,
  startOfYear,
  subDays,
  subMonths,
  subYears,
} from "date-fns";
import { useState } from "react";
import { DateRange } from "react-day-picker";

function Component() {
  const today = new Date();
  const yesterday = {
    from: subDays(today, 1),
    to: subDays(today, 1),
  };
  const last7Days = {
    from: subDays(today, 6),
    to: today,
  };
  const last30Days = {
    from: subDays(today, 29),
    to: today,
  };
  const monthToDate = {
    from: startOfMonth(today),
    to: today,
  };
  const lastMonth = {
    from: startOfMonth(subMonths(today, 1)),
    to: endOfMonth(subMonths(today, 1)),
  };
  const yearToDate = {
    from: startOfYear(today),
    to: today,
  };
  const lastYear = {
    from: startOfYear(subYears(today, 1)),
    to: endOfYear(subYears(today, 1)),
  };
  const [month, setMonth] = useState(today);
  const [date, setDate] = useState<DateRange | undefined>(last7Days);

return (
    <div>
      <div className="rounded-lg border border-border">
        <div className="flex max-sm:flex-col">
          <div className="relative border-border py-4 max-sm:order-1 max-sm:border-t sm:w-32">
            <div className="h-full border-border sm:border-e">
              <div className="flex flex-col px-2">
                <Button
                  variant="ghost"
                  size="sm"
                  className="w-full justify-start"
                  onClick={() => {
                    setDate({
                      from: today,
                      to: today,
                    });
                    setMonth(today);
                  }}
                >
                  Today
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  className="w-full justify-start"
                  onClick={() => {
                    setDate(yesterday);
                    setMonth(yesterday.to);
                  }}
                >
                  Yesterday
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  className="w-full justify-start"
                  onClick={() => {
                    setDate(last7Days);
                    setMonth(last7Days.to);
                  }}
                >
                  Last 7 days
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  className="w-full justify-start"
                  onClick={() => {
                    setDate(last30Days);
                    setMonth(last30Days.to);
                  }}
                >
                  Last 30 days
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  className="w-full justify-start"
                  onClick={() => {
                    setDate(monthToDate);
                    setMonth(monthToDate.to);
                  }}
                >
                  Month to date
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  className="w-full justify-start"
                  onClick={() => {
                    setDate(lastMonth);
                    setMonth(lastMonth.to);
                  }}
                >
                  Last month
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  className="w-full justify-start"
                  onClick={() => {
                    setDate(yearToDate);
                    setMonth(yearToDate.to);
                  }}
                >
                  Year to date
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  className="w-full justify-start"
                  onClick={() => {
                    setDate(lastYear);
                    setMonth(lastYear.to);
                  }}
                >
                  Last year
                </Button>
              </div>
            </div>
          </div>
          <Calendar
            mode="range"
            selected={date}
            onSelect={(newDate) => {
              if (newDate) {
                setDate(newDate);
              }
            }}
            month={month}
            onMonthChange={setMonth}
            className="p-2 bg-background"
            disabled={[\
              { after: today },\
            ]}
          />
        </div>
      </div>
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Range calendar with presets -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

More examples

Default Open page →

React App

August 2026

Calendar - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { Calendar } from "@/components/ui/calendar";
import { useState } from "react";

function Component() {
  const [date, setDate] = useState<Date | undefined>(new Date());

return (
    <div>
      <Calendar
        mode="single"
        selected={date}
        onSelect={setDate}
        className="rounded-lg border border-border p-2"
      />
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Calendar -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

Range calendar Open page →

React App

August 2026

Range calendar - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { Calendar } from "@/components/ui/calendar";
import { addDays } from "date-fns";
import { useState } from "react";
import { DateRange } from "react-day-picker";

function Component() {
  const today = new Date();
  const [date, setDate] = useState<DateRange | undefined>({
    from: today,
    to: addDays(today, 3),
  });

return (
    <div>
      <Calendar
        mode="range"
        selected={date}
        onSelect={setDate}
        className="rounded-lg border border-border p-2"
      />
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Range calendar -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

Disabled dates Open page →

React App

August 2026

Disabled dates - React DayPicker

Usage.tsxComponent.tsx

Copy

import { Calendar } from "@/components/ui/calendar";
import { addDays } from "date-fns";

function Component() {
  const today = new Date();

return (
    <div>
      <Calendar
        mode="range"
        disabled={[\
          { before: new Date() },\
          new Date(),\
          { dayOfWeek: [0, 6] },\
          {\
            from: addDays(today, 14),\
            to: addDays(today, 16),\
          },\
          {\
            from: addDays(today, 23),\
            to: addDays(today, 24),\
          },\
        ]}
        excludeDisabled
        className="rounded-lg border border-border p-2 bg-background"
      />
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Disabled dates -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

Multiple day selection Open page →

React App

August 2026

Multiple day selection - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { Calendar } from "@/components/ui/calendar";
import { addDays, subDays } from "date-fns";
import { useState } from "react";

function Component() {
  const today = new Date();
  const [date, setDate] = useState<Date[] | undefined>([\
    subDays(today, 17),\
    addDays(today, 2),\
    addDays(today, 6),\
    addDays(today, 8),\
  ]);

return (
    <div>
      <Calendar
        mode="multiple"
        selected={date}
        onSelect={setDate}
        className="rounded-lg border border-border p-2 bg-background"
      />
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Multiple day selection -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

Custom select day style Open page →

React App

August 2026

Custom select day style - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { Calendar } from "@/components/ui/calendar";
import { useState } from "react";

function Component() {
  const [date, setDate] = useState<Date | undefined>(new Date());

return (
    <div>
      <Calendar
        mode="single"
        selected={date}
        onSelect={setDate}
        className="rounded-lg border border-border p-2 bg-background"
        classNames={{
          day_button: "rounded-full",
        }}
      />
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Custom select day style -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

Right navigation Open page →

React App

August 2026

Right navigation - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { Calendar } from "@/components/ui/calendar";
import { useState } from "react";

function Component() {
  const [date, setDate] = useState<Date | undefined>(new Date());

return (
    <div>
      <Calendar
        mode="single"
        selected={date}
        onSelect={setDate}
        className="rounded-lg border border-border p-2 bg-background"
        classNames={{
          month_caption: "ms-2.5 me-20 justify-start",
          nav: "justify-end",
        }}
      />
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Right navigation -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

Monthly / yearly selects Open page →

React App

August2026August 2026

Monthly / yearly selects - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { Calendar } from "@/components/ui/calendar";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { useState } from "react";
import { DropdownNavProps, DropdownProps } from "react-day-picker";

function Component() {
  const [date, setDate] = useState<Date | undefined>(new Date());

const handleCalendarChange = (
    _value: string | number,
    _e: React.ChangeEventHandler<HTMLSelectElement>,
  ) => {
    const _event = {
      target: {
        value: String(_value),
      },
    } as React.ChangeEvent<HTMLSelectElement>;
    _e(_event);
  };

return (
    <div>
      <Calendar
        mode="single"
        selected={date}
        onSelect={setDate}
        className="rounded-lg border border-border p-2 bg-background"
        classNames={{
          month_caption: "mx-0",
        }}
        captionLayout="dropdown"
        defaultMonth={new Date()}
        startMonth={new Date(1980, 6)}
        hideNavigation
        components={{
          DropdownNav: (props: DropdownNavProps) => {
            return <div className="flex w-full items-center gap-2">{props.children}</div>;
          },
          Dropdown: (props: DropdownProps) => {
            return (
              <Select
                value={String(props.value)}
                onValueChange={(value) => {
                  if (props.onChange) {
                    handleCalendarChange(value, props.onChange);
                  }
                }}
              >
                <SelectTrigger className="h-8 w-fit font-medium first:grow">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent className="max-h-[min(26rem,var(--radix-select-content-available-height))]">
                  {props.options?.map((option) => (
                    <SelectItem
                      key={option.value}
                      value={String(option.value)}
                      disabled={option.disabled}
                    >
                      {option.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            );
          },
        }}
      />
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Monthly / yearly selects -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

Yearly select + nav Open page →

React App

August2026August 2026

Yearly select + nav - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

function Component() {
  const [date, setDate] = useState<Date | undefined>(new Date());

return (
    <div>
      <Calendar
        mode="single"
        selected={date}
        onSelect={setDate}
        className="rounded-lg border border-border p-2 bg-background"
        captionLayout="dropdown-years"
        defaultMonth={new Date()}
        startMonth={new Date(1980, 6)}
        components={{
          DropdownNav: (props: DropdownNavProps) => {
            return (
              <div className="flex w-full items-center justify-center gap-3 [&>span]:text-sm [&>span]:font-medium">
                {props.children}
              </div>
            );
          },
          YearsDropdown: (props: DropdownProps) => {
            return (
              <Select
                value={String(props.value)}
                onValueChange={(value) => {
                  if (props.onChange) {
                    handleCalendarChange(value, props.onChange);
                  }
                }}
              >
                <SelectTrigger className="h-8 w-fit font-medium">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent className="max-h-[min(26rem,var(--radix-select-content-available-height))]">
                  {props.options?.map((option) => (
                    <SelectItem
                      key={option.value}
                      value={String(option.value)}
                      disabled={option.disabled}
                    >
                      {option.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            );
          },
        }}
      />
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Yearly select + nav -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

Weekly numbers Open page →

React App

August 2026

Su Mo Tu We Th Fr Sa
31 26 27 28 29 30 31 1
32 2 3 4 5 6 7 8
33 9 10 11 12 13 14 15
34 16 17 18 19 20 21 22
35 23 24 25 26 27 28 29
36 30 31 1 2 3 4 5

Weekly numbers - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { Calendar } from "@/components/ui/calendar";
import { useState } from "react";
import type { WeekNumberProps } from "react-day-picker";

function Component() {
  const [date, setDate] = useState<Date | undefined>(new Date());

return (
    <div>
      <Calendar
        mode="single"
        selected={date}
        onSelect={setDate}
        className="rounded-lg border border-border p-2 bg-background"
        fixedWeeks
        showWeekNumber
        components={{
          WeekNumber: ({ week, ...props }: WeekNumberProps) => {
            return <th {...props}>{week.weekNumber}</th>;
          },
        }}
      />
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Weekly numbers -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

With button Open page →

React App

July 2026

Su Mo Tu We Th Fr Sa
28 29 30 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31 1

Today

With button - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { addDays } from "date-fns";
import { useState } from "react";

function Component() {
  const today = new Date();
  const selectedDay = addDays(today, -28);
  const [month, setMonth] = useState(selectedDay);
  const [date, setDate] = useState<Date | undefined>(selectedDay);

return (
    <div>
      <div className="rounded-lg border border-border p-2">
        <Calendar
          className="bg-background"
          mode="single"
          selected={date}
          onSelect={setDate}
          month={month}
          onMonthChange={setMonth}
        />
        <Button
          variant="outline"
          size="sm"
          className="my-1"
          onClick={() => {
            setDate(today);
            setMonth(today);
          }}
        >
          Today
        </Button>
      </div>
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        With button -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

With today button Open page →

React App

July 2026

Today

With button - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

export { Component };

With date input Open page →

React App

August 2026

Enter date

Date input - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { Calendar } from "@/components/ui/calendar";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { format } from "date-fns";
import { CalendarIcon } from "lucide-react";
import { useEffect, useId, useState } from "react";

function Component() {
  const id = useId();
  const today = new Date();
  const [month, setMonth] = useState(today);
  const [date, setDate] = useState<Date | undefined>(today);
  const [inputValue, setInputValue] = useState("");

const handleDayPickerSelect = (date: Date | undefined) => {
    if (!date) {
      setInputValue("");
      setDate(undefined);
    } else {
      setDate(date);
      setMonth(date);
      setInputValue(format(date, "yyyy-MM-dd"));
    }
  };

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value;
    setInputValue(value);

if (value) {
      const parsedDate = new Date(value);
      setDate(parsedDate);
      setMonth(parsedDate);
    } else {
      setDate(undefined);
    }
  };

useEffect(() => {
    setInputValue(format(today, "yyyy-MM-dd"));
  }, []);

return (
    <div>
      <div className="rounded-lg border border-border">
        <Calendar
          mode="single"
          className="p-2 bg-background"
          selected={date}
          onSelect={handleDayPickerSelect}
          month={month}
          onMonthChange={setMonth}
        />
        <div className="border-t border-border p-3">
          <div className="flex items-center gap-3">
            <Label htmlFor={id} className="text-xs">
              Enter date
            </Label>
            <div className="relative grow">
              <Input
                id={id}
                type="date"
                value={inputValue}
                onChange={handleInputChange}
                className="peer ps-9 [&::-webkit-calendar-picker-indicator]:hidden"
                aria-label="Select date"
              />
              <div className="pointer-events-none absolute inset-y-0 start-0 flex items-center justify-center ps-3 text-muted-foreground/80 peer-disabled:opacity-50">
                <CalendarIcon size={16} strokeWidth={2} aria-hidden="true" />
              </div>
            </div>
          </div>
        </div>
      </div>
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Date input -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

With time input Open page →

React App

August 2026

Enter time

Time input - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { Calendar } from "@/components/ui/calendar";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Clock } from "lucide-react";
import { useId, useState } from "react";

function Component() {
  const id = useId();
  const [date, setDate] = useState<Date | undefined>(new Date());

return (
    <div>
      <div className="rounded-lg border border-border">
        <Calendar mode="single" className="p-2 bg-background" selected={date} onSelect={setDate} />
        <div className="border-t border-border p-3">
          <div className="flex items-center gap-3">
            <Label htmlFor={id} className="text-xs">
              Enter time
            </Label>
            <div className="relative grow">
              <Input
                id={id}
                type="time"
                step="1"
                defaultValue="12:00:00"
                className="peer ps-9 [&::-webkit-calendar-picker-indicator]:hidden"
              />
              <div className="pointer-events-none absolute inset-y-0 start-0 flex items-center justify-center ps-3 text-muted-foreground/80 peer-disabled:opacity-50">
                <Clock size={16} strokeWidth={2} aria-hidden="true" />
              </div>
            </div>
          </div>
        </div>
      </div>
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Time input -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

Advanced selection Open page →

React App

August 2026

Advanced selection - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from "@/components/ui/collapsible";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
  eachMonthOfInterval,
  eachYearOfInterval,
  endOfYear,
  format,
  isAfter,
  isBefore,
  startOfYear,
} from "date-fns";
import { ChevronDown } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { CaptionLabelProps, MonthGridProps } from "react-day-picker";

function Component() {
  const today = new Date();
  const [month, setMonth] = useState(today);
  const [date, setDate] = useState<Date | undefined>(today);
  const [isYearView, setIsYearView] = useState(false);
  const startDate = new Date(1980, 6);
  const endDate = new Date(2030, 6);

const years = eachYearOfInterval({
    start: startOfYear(startDate),
    end: endOfYear(endDate),
  });

return (
    <div>
      <Calendar
        mode="single"
        selected={date}
        onSelect={setDate}
        month={month}
        onMonthChange={setMonth}
        defaultMonth={new Date()}
        startMonth={startDate}
        endMonth={endDate}
        className="overflow-hidden rounded-lg border border-border p-2 bg-background"
        classNames={{
          month_caption: "ms-2.5 me-20 justify-start",
          nav: "justify-end",
        }}
        components={{
          CaptionLabel: (props: CaptionLabelProps) => (
            <CaptionLabel isYearView={isYearView} setIsYearView={setIsYearView} {...props} />
          ),
          MonthGrid: (props: MonthGridProps) => {
            return (
              <MonthGrid
                className={props.className}
                isYearView={isYearView}
                setIsYearView={setIsYearView}
                startDate={startDate}
                endDate={endDate}
                years={years}
                currentYear={month.getFullYear()}
                currentMonth={month.getMonth()}
                onMonthSelect={(selectedMonth: Date) => {
                  setMonth(selectedMonth);
                  setIsYearView(false);
                }}
              >
                {props.children}
              </MonthGrid>
            );
          },
        }}
      />
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Advanced selection -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

function MonthGrid({
  className,
  children,
  isYearView,
  startDate,
  endDate,
  years,
  currentYear,
  currentMonth,
  onMonthSelect,
}: {
  className?: string;
  children: React.ReactNode;
  isYearView: boolean;
  setIsYearView: React.Dispatch<React.SetStateAction<boolean>>;
  startDate: Date;
  endDate: Date;
  years: Date[];
  currentYear: number;
  currentMonth: number;
  onMonthSelect: (date: Date) => void;
}) {
  const currentYearRef = useRef<HTMLDivElement>(null);
  const currentMonthButtonRef = useRef<HTMLButtonElement>(null);
  const scrollAreaRef = useRef<HTMLDivElement>(null);

useEffect(() => {
    if (isYearView && currentYearRef.current && scrollAreaRef.current) {
      const viewport = scrollAreaRef.current.querySelector(
        "[data-radix-scroll-area-viewport]",
      ) as HTMLElement;
      if (viewport) {
        const yearTop = currentYearRef.current.offsetTop;
        viewport.scrollTop = yearTop;
      }
      setTimeout(() => {
        currentMonthButtonRef.current?.focus();
      }, 100);
    }
  }, [isYearView]);

return (
    <div className="relative">
      <table className={className}>{children}</table>
      {isYearView && (
        <div className="absolute inset-0 z-20 -mx-2 -mb-2 bg-background">
          <ScrollArea ref={scrollAreaRef} className="h-full">
            {years.map((year) => {
              const months = eachMonthOfInterval({
                start: startOfYear(year),
                end: endOfYear(year),
              });
              const isCurrentYear = year.getFullYear() === currentYear;

return (
                <div key={year.getFullYear()} ref={isCurrentYear ? currentYearRef : undefined}>
                  <CollapsibleYear title={year.getFullYear().toString()} open={isCurrentYear}>
                    <div className="grid grid-cols-3 gap-2">
                      {months.map((month) => {
                        const isDisabled = isBefore(month, startDate) || isAfter(month, endDate);
                        const isCurrentMonth =
                          month.getMonth() === currentMonth && year.getFullYear() === currentYear;

return (
                          <Button
                            key={month.getTime()}
                            ref={isCurrentMonth ? currentMonthButtonRef : undefined}
                            variant={isCurrentMonth ? "default" : "outline"}
                            size="sm"
                            className="h-7"
                            disabled={isDisabled}
                            onClick={() => onMonthSelect(month)}
                          >
                            {format(month, "MMM")}
                          </Button>
                        );
                      })}
                    </div>
                  </CollapsibleYear>
                </div>
              );
            })}
          </ScrollArea>
        </div>
      )}
    </div>
  );
}

function CaptionLabel({
  children,
  isYearView,
  setIsYearView,
}: {
  isYearView: boolean;
  setIsYearView: React.Dispatch<React.SetStateAction<boolean>>;
} & React.HTMLAttributes<HTMLSpanElement>) {
  return (
    <Button
      className="-ms-2 flex items-center gap-2 text-sm font-medium hover:bg-transparent data-[state=open]:text-muted-foreground/80 [&[data-state=open]>svg]:rotate-180"
      variant="ghost"
      size="sm"
      onClick={() => setIsYearView((prev) => !prev)}
      data-state={isYearView ? "open" : "closed"}
    >
      {children}
      <ChevronDown
        size={16}
        strokeWidth={2}
        className="shrink-0 text-muted-foreground/80 transition-transform duration-200"
        aria-hidden="true"
      />
    </Button>
  );
}

function CollapsibleYear({
  title,
  children,
  open,
}: {
  title: string;
  children: React.ReactNode;
  open?: boolean;
}) {
  return (
    <Collapsible className="border-t border-border px-2 py-1.5" defaultOpen={open}>
      <CollapsibleTrigger asChild>
        <Button
          className="flex w-full justify-start gap-2 text-sm font-medium hover:bg-transparent [&[data-state=open]>svg]:rotate-180"
          variant="ghost"
          size="sm"
        >
          <ChevronDown
            size={16}
            strokeWidth={2}
            className="shrink-0 text-muted-foreground/80 transition-transform duration-200"
            aria-hidden="true"
          />
          {title}
        </Button>
      </CollapsibleTrigger>
      <CollapsibleContent className="overflow-hidden px-3 py-1 text-sm transition-all data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down">
        {children}
      </CollapsibleContent>
    </Collapsible>
  );
}

export { Component };

Appointment picker Open page →

React App

August 2026

Friday, 7

09:0009:3010:0010:3011:0011:3012:0012:3013:0013:3014:0014:3015:0015:3016:0016:3017:0017:30

Appointment picker - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { ScrollArea } from "@/components/ui/scroll-area";
import { format } from "date-fns";
import { useState } from "react";

function Component() {
  const today = new Date();
  const [date, setDate] = useState<Date>(today);
  const [time, setTime] = useState<string | null>(null);

const timeSlots = [\
    { time: "09:00", available: false },\
    { time: "09:30", available: false },\
    { time: "10:00", available: true },\
    { time: "10:30", available: true },\
    { time: "11:00", available: true },\
    { time: "11:30", available: true },\
    { time: "12:00", available: false },\
    { time: "12:30", available: true },\
    { time: "13:00", available: true },\
    { time: "13:30", available: true },\
    { time: "14:00", available: true },\
    { time: "14:30", available: false },\
    { time: "15:00", available: false },\
    { time: "15:30", available: true },\
    { time: "16:00", available: true },\
    { time: "16:30", available: true },\
    { time: "17:00", available: true },\
    { time: "17:30", available: true },\
  ];

return (
    <div>
      <div className="rounded-lg border border-border">
        <div className="flex max-sm:flex-col">
          <Calendar
            mode="single"
            selected={date}
            onSelect={(newDate) => {
              if (newDate) {
                setDate(newDate);
                setTime(null);
              }
            }}
            className="p-2 sm:pe-5 bg-background"
            disabled={[\
              { before: today },\
            ]}
          />
          <div className="relative w-full max-sm:h-48 sm:w-40">
            <div className="absolute inset-0 border-border py-4 max-sm:border-t">
              <ScrollArea className="h-full border-border sm:border-s">
                <div className="space-y-3">
                  <div className="flex h-5 shrink-0 items-center px-5">
                    <p className="text-sm font-medium">{format(date, "EEEE, d")}</p>
                  </div>
                  <div className="grid gap-1.5 px-5 max-sm:grid-cols-2">
                    {timeSlots.map(({ time: timeSlot, available }) => (
                      <Button
                        key={timeSlot}
                        variant={time === timeSlot ? "default" : "outline"}
                        size="sm"
                        className="w-full"
                        onClick={() => setTime(timeSlot)}
                        disabled={!available}
                      >
                        {timeSlot}
                      </Button>
                    ))}
                  </div>
                </div>
              </ScrollArea>
            </div>
          </div>
        </div>
      </div>
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Appointment picker -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

Calendar with presets Open page →

React App

TodayYesterdayLast weekLast monthLast year

August 2026

Calendar with presets - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { subDays, subMonths, subYears } from "date-fns";
import { useState } from "react";

function Component() {
  const today = new Date();
  const yesterday = subDays(today, 1);
  const lastWeek = subDays(today, 7);
  const lastMonth = subMonths(today, 1);
  const lastYear = subYears(today, 1);
  const [month, setMonth] = useState(today);
  const [date, setDate] = useState<Date>(today);

return (
    <div>
      <div className="rounded-lg border border-border">
        <div className="flex max-sm:flex-col">
          <div className="relative border-border py-4 max-sm:order-1 max-sm:border-t sm:w-32">
            <div className="h-full border-border sm:border-e">
              <div className="flex flex-col px-2">
                <Button
                  variant="ghost"
                  size="sm"
                  className="w-full justify-start"
                  onClick={() => {
                    setDate(today);
                    setMonth(today);
                  }}
                >
                  Today
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  className="w-full justify-start"
                  onClick={() => {
                    setDate(yesterday);
                    setMonth(yesterday);
                  }}
                >
                  Yesterday
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  className="w-full justify-start"
                  onClick={() => {
                    setDate(lastWeek);
                    setMonth(lastWeek);
                  }}
                >
                  Last week
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  className="w-full justify-start"
                  onClick={() => {
                    setDate(lastMonth);
                    setMonth(lastMonth);
                  }}
                >
                  Last month
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  className="w-full justify-start"
                  onClick={() => {
                    setDate(lastYear);
                    setMonth(lastYear);
                  }}
                >
                  Last year
                </Button>
              </div>
            </div>
          </div>
          <Calendar
            mode="single"
            selected={date}
            onSelect={(newDate) => {
              if (newDate) {
                setDate(newDate);
              }
            }}
            month={month}
            onMonthChange={setMonth}
            className="p-2 bg-background"
            disabled={[\
              { after: today },\
            ]}
          />
        </div>
      </div>
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Calendar with presets -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

Two months calendar Open page →

React App

August 2026

Su Mo Tu We Th Fr Sa
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31

September 2026

Su Mo Tu We Th Fr Sa
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30

Two months calendar - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

function Component() {
  const today = new Date();
  const [date, setDate] = useState<DateRange | undefined>({
    from: today,
    to: addDays(today, 25),
  });

return (
    <div>
      <Calendar
        mode="range"
        selected={date}
        onSelect={setDate}
        numberOfMonths={2}
        pagedNavigation
        showOutsideDays={false}
        className="rounded-lg border border-border p-2 bg-background"
        classNames={{
          months: "gap-8",
          month:
            "relative first-of-type:before:hidden before:absolute max-sm:before:inset-x-2 max-sm:before:h-px max-sm:before:-top-2 sm:before:inset-y-2 sm:before:w-px before:bg-border sm:before:-left-4",
        }}
      />
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Two months calendar -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

Three months calendar Open page →

React App

August 2026

September 2026

October 2026

Su Mo Tu We Th Fr Sa
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

Three months calendar - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

function Component() {
  const today = new Date();
  const [date, setDate] = useState<DateRange | undefined>({
    from: today,
    to: addDays(today, 48),
  });

return (
    <div>
      <Calendar
        mode="range"
        selected={date}
        onSelect={setDate}
        numberOfMonths={3}
        pagedNavigation
        showOutsideDays={false}
        className="rounded-lg border border-border p-2 bg-background"
        classNames={{
          months: "sm:flex-col md:flex-row gap-8",
          month:
            "relative first-of-type:before:hidden before:absolute max-md:before:inset-x-2 max-md:before:h-px max-md:before:-top-4 md:before:inset-y-2 md:before:w-px before:bg-border md:before:-left-4",
        }}
      />
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Three months calendar -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

Pricing calendar Open page →

React App

August 2026

Su Mo Tu We Th Fr Sa
1
2 3 4 5 6 7$118 8$147
9$193 10$164 11$104 12$171 13$108 14$100 15$194
16$119 17$173 18$186 19$130 20$145 21$199 22$154
23$151 24$191 25$175 26$152 27$176 28$137 29$193
30$128 31$145

September 2026

Su Mo Tu We Th Fr Sa
1$155 2$187 3$154 4$110 5$107
6$101 7$174 8$183 9$174 10$135 11$162 12$92
13$141 14$131 15$80 16$189 17$192 18$145 19$177
20$146 21$93 22$136 23$127 24$158 25$144 26$86
27$179 28$87 29$190 30$157

Pricing calendar - React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { cn } from "@/lib/utils";
import { Calendar } from "@/components/ui/calendar";
import { format } from "date-fns";
import { useEffect, useState } from "react";
import { DayButtonProps } from "react-day-picker";

const GOOD_PRICE_THRESHOLD = 100;

function Component() {
  const today = new Date();
  const [date, setDate] = useState<Date | undefined>(today);

const [mockPriceData, setMockPriceData] = useState<Record<string, number>>({});
  useEffect(() => {
    const generateMockPriceData = () => {
      const data: Record<string, number> = {};

for (let i = 0; i < 180; i++) {
        const date = new Date(today);
        date.setDate(today.getDate() + i);
        const dateKey = format(date, "yyyy-MM-dd");
        const randomPrice = Math.floor(Math.random() * (200 - 80 + 1)) + 80;
        data[dateKey] = randomPrice;
      }
      return data;
    };
    setMockPriceData(generateMockPriceData());
  }, []);

const isDateDisabled = (date: Date) => {
    return !mockPriceData[format(date, "yyyy-MM-dd")];
  };

return (
    <div>
      <Calendar
        mode="single"
        selected={date}
        onSelect={setDate}
        numberOfMonths={2}
        pagedNavigation
        showOutsideDays={false}
        className="rounded-lg border border-border p-2 bg-background"
        classNames={{
          months: "sm:flex-col md:flex-row gap-8",
          month:
            "relative first-of-type:before:hidden before:absolute max-md:before:inset-x-2 max-md:before:inset-y-2 md:before:w-px before:bg-border md:before:-left-4",
          weekday: "w-12",
          day_button: "size-12",
          today: "*:after:hidden",
        }}
        components={{
          DayButton: (props: DayButtonProps) => <DayButton {...props} prices={mockPriceData} />,
        }}
        disabled={isDateDisabled}
      />
      <p
        className="mt-4 text-center text-xs text-muted-foreground"
        role="region"
        aria-live="polite"
      >
        Pricing calendar -{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

function DayButton(props: DayButtonProps & { prices: Record<string, number> }) {
  const { day, modifiers, prices, ...buttonProps } = props;
  const price = prices[format(day.date, "yyyy-MM-dd")];
  const isGoodPrice = price < GOOD_PRICE_THRESHOLD;

return (
    <button {...buttonProps}>
      <span className="flex flex-col">
        {props.children}
        {price && (
          <span
            className={cn(
              "text-[10px] font-medium",
              isGoodPrice
                ? "text-emerald-500"
                : "text-muted-foreground group-data-[selected]:text-primary-foreground/70",
            )}
          >
            ${price}
          </span>
        )}
      </span>
    </button>
  );
}

export { Component };

Date picker Open page →

React App

Date pickerPick a date

Built with React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Label } from "@/components/ui/label";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { format } from "date-fns";
import { CalendarIcon } from "lucide-react";
import { useId, useState } from "react";

function Component() {
  const id = useId();
  const [date, setDate] = useState<Date | undefined>();

return (
    <div>
      <div className="space-y-2">
        <Label htmlFor={id}>Date picker</Label>
        <Popover>
          <PopoverTrigger asChild>
            <Button
              id={id}
              variant={"outline"}
              className={cn(
                "group w-full justify-between bg-background px-3 font-normal outline-offset-0 hover:bg-background focus-visible:border-ring focus-visible:outline-[3px] focus-visible:outline-ring/20",
                !date && "text-muted-foreground",
              )}
            >
              <span className={cn("truncate", !date && "text-muted-foreground")}>
                {date ? format(date, "PPP") : "Pick a date"}
              </span>
              <CalendarIcon
                size={16}
                strokeWidth={2}
                className="shrink-0 text-muted-foreground/80 transition-colors group-hover:text-foreground"
                aria-hidden="true"
              />
            </Button>
          </PopoverTrigger>
          <PopoverContent className="w-auto p-2" align="start">
            <Calendar mode="single" selected={date} onSelect={setDate} />
          </PopoverContent>
        </Popover>
      </div>
      <p className="mt-2 text-xs text-muted-foreground" role="region" aria-live="polite">
        Built with{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

Date range picker Open page →

React App

Date range pickerPick a date range

Built with React DayPicker

Usage.tsxComponent.tsx

Copy

"use client";

import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Label } from "@/components/ui/label";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { format } from "date-fns";
import { CalendarIcon } from "lucide-react";
import { useId, useState } from "react";
import { DateRange } from "react-day-picker";

function Component() {
  const id = useId();
  const [date, setDate] = useState<DateRange | undefined>();

return (
    <div>
      <div className="space-y-2">
        <Label htmlFor={id}>Date range picker</Label>
        <Popover>
          <PopoverTrigger asChild>
            <Button
              id={id}
              variant={"outline"}
              className={cn(
                "group w-full justify-between bg-background px-3 font-normal outline-offset-0 hover:bg-background focus-visible:border-ring focus-visible:outline-[3px] focus-visible:outline-ring/20",
                !date && "text-muted-foreground",
              )}
            >
              <span className={cn("truncate", !date && "text-muted-foreground")}>
                {date?.from ? (
                  date.to ? (
                    <>
                      {format(date.from, "LLL dd, y")} - {format(date.to, "LLL dd, y")}
                    </>
                  ) : (
                    format(date.from, "LLL dd, y")
                  )
                ) : (
                  "Pick a date range"
                )}
              </span>
              <CalendarIcon
                size={16}
                strokeWidth={2}
                className="shrink-0 text-muted-foreground/80 transition-colors group-hover:text-foreground"
                aria-hidden="true"
              />
            </Button>
          </PopoverTrigger>
          <PopoverContent className="w-auto p-2" align="start">
            <Calendar mode="range" selected={date} onSelect={setDate} />
          </PopoverContent>
        </Popover>
      </div>
      <p className="mt-2 text-xs text-muted-foreground" role="region" aria-live="polite">
        Built with{" "}
        <a
          className="underline hover:text-foreground"
          href="https://daypicker.dev/"
          target="_blank"
          rel="noopener nofollow"
        >
          React DayPicker
        </a>
      </p>
    </div>
  );
}

export { Component };

Dependencies

lucide-react react-day-picker date-fns

Source

originui.com

Published

1/21/2025

Similar components

Apple Calendar Picker

124

Calendar

2

Calendar

31

Calendar With Presets

42

Dropdown Range Date Picker

49

Select

4

Tour

75

Calendar Date Picker

15

Assisted Password Confirmation

469

Breadcrumb

32

Integrations Grid

76

Animated Typewriter Text

48

Profile Card

174

Ruixen Moon Chat

554

Glass Card

183

SaaS Template

1.2k

Toast Notification

13

Avatar

82

Elegant Dark Pattern

201

Calendar input

11

Modern Login & Signup

508

FAQ roller

90

Footer section

1.0k

Price Target Fan

67

Loading more

Explore more

Part of Origin UI — browse the full library on 21st.dev.

Sidebar components95 Calendar components239 Date Picker components250 shadcn/ui components1043 Range Slider components101

Calendar [React Day Picker] | Community Components | 21st