Calendar

A date field component that lets users select dates and date ranges, navigate months, and pick a month or year directly.

Default

Built on React DayPicker. A single date is selected with mode="single".

August 2026

tsx

import * as React from "react";
import { Calendar } from "@hummingbirdui/react";

export default function CalendarDefault() {
  const [date, setDate] = React.useState<Date | undefined>(new Date());

  return (
    <Calendar
      mode="single"
      selected={date}
      onSelect={setDate}
      className="mx-auto rounded-lg border border-default"
    />
  );
}

Range Calendar

mode="range" selects a start and end date, and numberOfMonths shows several months side by side.

January 2026
February 2026

tsx

import * as React from "react";
import { addDays } from "date-fns";
import { type DateRange } from "react-day-picker";

import { Calendar } from "@hummingbirdui/react";
import { Card } from "@hummingbirdui/react";

export default function CalendarRange() {
  const [dateRange, setDateRange] = React.useState<DateRange | undefined>({
    from: new Date(new Date().getFullYear(), 0, 12),
    to: addDays(new Date(new Date().getFullYear(), 0, 12), 30),
  });

  return (
    <Card className="mx-auto w-fit p-0">
      <Calendar
        mode="range"
        defaultMonth={dateRange?.from}
        selected={dateRange}
        onSelect={setDateRange}
        numberOfMonths={2}
        disabled={(date) => date > new Date() || date < new Date("1900-01-01")}
      />
    </Card>
  );
}

Month and Year Selector

captionLayout="dropdown" replaces the caption label with month and year dropdowns.

August 2026

tsx

import { Calendar } from "@hummingbirdui/react";

export default function CalendarCaption() {
  return (
    <Calendar
      mode="single"
      className="mx-auto rounded-lg border border-default"
      captionLayout="dropdown"
    />
  );
}

Calendar Presets

Buttons outside the calendar can set the selected date and visible month through the controlled selected and month props.

August 2026

tsx

import * as React from "react";
import { addDays } from "date-fns";

import { Button, Calendar, Card } from "@hummingbirdui/react";

export default function CalendarWithPresets() {
  const [date, setDate] = React.useState<Date | undefined>(
    new Date(new Date().getFullYear(), 1, 12),
  );
  const [currentMonth, setCurrentMonth] = React.useState<Date>(
    new Date(new Date().getFullYear(), new Date().getMonth(), 1),
  );

  return (
    <Card className="mx-auto w-fit max-w-75">
      <Card.Body className="p-0">
        <Calendar
          mode="single"
          selected={date}
          onSelect={setDate}
          month={currentMonth}
          onMonthChange={setCurrentMonth}
          fixedWeeks
          className="w-full"
        />
      </Card.Body>
      <Card.Footer className="flex flex-wrap gap-2 border-t border-default">
        {[
          { label: "Today", value: 0 },
          { label: "Tomorrow", value: 1 },
          { label: "In 3 days", value: 3 },
          { label: "In a week", value: 7 },
          { label: "In 2 weeks", value: 14 },
        ].map((preset) => (
          <Button
            key={preset.value}
            variant="outline"
            size="sm"
            onClick={() => {
              const newDate = addDays(new Date(), preset.value);
              setDate(newDate);
              setCurrentMonth(
                new Date(newDate.getFullYear(), newDate.getMonth(), 1),
              );
            }}
          >
            {preset.label}
          </Button>
        ))}
      </Card.Footer>
    </Card>
  );
}

Calendar With Time

A calendar combined with time inputs for picking a date and time together.

August 2026

tsx

import * as React from "react";
import { Calendar, Card, Field, Input, InputIcon } from "@hummingbirdui/react";
import { Clock2Icon } from "lucide-react";

export default function CalendarWithTime() {
  const [date, setDate] = React.useState<Date | undefined>(
    new Date(new Date().getFullYear(), new Date().getMonth(), 12),
  );

  return (
    <Card className="mx-auto w-fit">
      <Card.Body className="p-0">
        <Calendar
          mode="single"
          selected={date}
          onSelect={setDate}
          className="w-full"
        />
      </Card.Body>
      <Card.Footer className="border-t border-default">
        <div>
          <Field className="mb-3">
            <Field.Label htmlFor="time-from">Start Time</Field.Label>
            <InputIcon>
              <Input
                id="time-from"
                type="time"
                step="1"
                defaultValue="10:30:00"
                className="appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
              />
              <InputIcon.End>
                <Clock2Icon className="text-muted size-4" />
              </InputIcon.End>
            </InputIcon>
          </Field>
          <Field>
            <Field.Label htmlFor="time-to">End Time</Field.Label>
            <InputIcon>
              <Input
                id="time-to"
                type="time"
                step="1"
                defaultValue="12:30:00"
                className="appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
              />
              <InputIcon.End>
                <Clock2Icon className="text-muted size-4" />
              </InputIcon.End>
            </InputIcon>
          </Field>
        </div>
      </Card.Footer>
    </Card>
  );
}

Booked dates

The disabled and modifiers props mark dates as unavailable.

January 2026

tsx

import * as React from "react";

import { Calendar, Card } from "@hummingbirdui/react";

export default function CalendarBookedDates() {
  const [date, setDate] = React.useState<Date | undefined>(
    new Date(new Date().getFullYear(), 0, 6),
  );
  const bookedDates = Array.from(
    { length: 15 },
    (_, i) => new Date(new Date().getFullYear(), 0, 12 + i),
  );

  return (
    <Card className="mx-auto w-fit p-0">
      <Card.Body className="p-0">
        <Calendar
          mode="single"
          defaultMonth={date}
          selected={date}
          onSelect={setDate}
          disabled={bookedDates}
          modifiers={{
            booked: bookedDates,
          }}
          modifiersClassNames={{
            booked: "[&>button]:line-through opacity-100",
          }}
        />
      </Card.Body>
    </Card>
  );
}

Week numbers

showWeekNumber adds an ISO week number column.

January 2026
01
02
03
04
05

tsx

import * as React from "react";

import { Card, Calendar } from "@hummingbirdui/react";

export default function CalendarWeekNumbers() {
  const [date, setDate] = React.useState<Date | undefined>(
    new Date(new Date().getFullYear(), 0, 12),
  );

  return (
    <Card className="mx-auto w-fit p-0">
      <Card.Body className="p-0">
        <Calendar
          mode="single"
          defaultMonth={date}
          selected={date}
          onSelect={setDate}
          showWeekNumber
        />
      </Card.Body>
    </Card>
  );
}

API Reference

Calendar forwards all props to React DayPicker.

CSS variables

The calendar class exposes these CSS variables, which can be overridden to modify the calendar's appearance. Read more about customizing with CSS variables here.

.calendar {
  --calendar-bg: var(--background-color-default);
  --calendar-color: var(--text-color-default);
  --calendar-muted-color: var(--text-color-muted);
  --calendar-padding: --spacing(2);
  --calendar-border-radius: var(--radius-lg);
  --calendar-cell-size: --spacing(9);
  --calendar-cell-radius: var(--radius-md);
  --calendar-disabled-opacity: 0.5;
  --calendar-outside-opacity: 0.7;
  --calendar-nav-btn-size: --spacing(9);
  --calendar-nav-btn-icon-size: --spacing(4);
  --calendar-caption-height: --spacing(9);
  --calendar-caption-font-size: var(--text-sm);
  --calendar-caption-font-weight: var(--font-weight-medium);
  --calendar-caption-icon-size: --spacing(3.5);
  --calendar-caption-icon-color: var(--text-color-muted);
  --calendar-weekday-color: var(--text-color-muted);
  --calendar-weekday-font-size: var(--text-xs);
  --calendar-weekday-font-weight: var(--font-weight-normal);
  --calendar-day-color: var(--text-color-default);
  --calendar-day-font-weight: var(--font-weight-normal);
  --calendar-day-selected-color: var(--color-white);
  --calendar-day-selected-bg: var(--color-primary);
  --calendar-day-range-color: var(--text-color-default);
  --calendar-day-range-bg: var(--background-color-muted);
  --calendar-week-number-color: var(--text-color-muted);
  --calendar-week-number-font-size: var(--text-xs);
}