DateForgeStorybook

Examples

Likely one of these fits your case.

These are just starting points. Mix the modules however you like — booking, dashboards, forms, scheduling, whatever your product needs. Storybook is the open playground; this page is finished recipes you can copy and tweak.

$npm i @dateforge/react-calendar
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition

The basics

Use this when
You're starting a new flow and just need a working date picker.
What it demonstrates
Bare minimum composition — Calendar shell + nav + days + selected dates.
singlestarter
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarSelectedDates } from "@dateforge/react-calendar/modules";

export function TheBasicsExample() {
  const [basicDate, setBasicDate] = useState<Date | null>(new Date());

  return (
    <Calendar mode="single" value={basicDate} onChange={setBasicDate}>
      <CalendarNav showMonthPicker compactYears />
      <CalendarDays />
      <CalendarSelectedDates allowClear={false} />
    </Calendar>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition

Stay booking

Use this when
Lodging or short-stay rentals where guests pick check-in and check-out.
What it demonstrates
Range mode with disabled past dates, basic stay presets, and a clear/animated selected summary.
appearance: soft
rangebookingpresets
Code
import { useMemo, useState } from "react";
import { Calendar, basicPresets, createDisabled } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarPresets, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import { snow } from "@dateforge/react-calendar/themes";
import { soft } from "@dateforge/react-calendar/appearances";

export function StayBookingExample() {
  const [stayRange, setStayRange] = useState<{ from: Date | null; to: Date | null }>({ from: null, to: null });

  const noPast = useMemo(() => {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    return createDisabled({ before: today });
  }, []);

  return (
    <Calendar mode="range" value={stayRange} onChange={setStayRange} disabled={noPast} theme={snow} appearance={soft}>
      <CalendarNav showMonthPicker compactYears clear />
      <CalendarPresets presets={basicPresets.slice(4, 9)} />
      <CalendarDays />
      <CalendarSelectedDates allowClear allowNavigate animated />
    </Calendar>
  );
}
May
May
11
11
Composition

Flight search

Use this when
Booking flow needing departure and return without a full second month grid.
What it demonstrates
Split bound tracks (bound="from" / bound="to") for compact range selection across two columns.
theme: temporalappearance: compact
rangemobile
Code
import { useMemo, useState } from "react";
import { Calendar, createDisabled } from "@dateforge/react-calendar";
import { CalendarDaysTrack, CalendarMonthsTrack, CalendarNav, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import { temporal } from "@dateforge/react-calendar/themes";
import { compact } from "@dateforge/react-calendar/appearances";

export function FlightSearchExample() {
  const [flightRange, setFlightRange] = useState<{ from: Date | null; to: Date | null }>({ from: null, to: null });

  const noPast = useMemo(() => {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    return createDisabled({ before: today });
  }, []);

  return (
    <Calendar mode="range" value={flightRange} onChange={setFlightRange} disabled={noPast} theme={temporal} appearance={compact}>
      <CalendarNav label="Departure" monthLabel yearLabel clear />
      <CalendarMonthsTrack bound="from" short />
      <CalendarDaysTrack bound="from" showMonthLabel />
      <CalendarNav label="Return" monthLabel yearLabel />
      <CalendarMonthsTrack bound="to" short />
      <CalendarDaysTrack bound="to" showMonthLabel />
      <CalendarSelectedDates allowClear animated />
    </Calendar>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition

Two-month stay search

Use this when
Desktop booking with side-by-side months and a single shared range.
What it demonstrates
cols={2} with two CalendarDays (offset 0 and 1) and one continuous range value.
theme: snowappearance: soft
2 monthsdesktop
Code
import { useMemo, useState } from "react";
import { Calendar, createDisabled } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarSelectedDates } from "@dateforge/react-calendar/modules";

export function TwomonthStaySearchExample() {
  const [twoMonthRange, setTwoMonthRange] = useState<{ from: Date | null; to: Date | null }>({ from: null, to: null });

  const noPast = useMemo(() => {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    return createDisabled({ before: today });
  }, []);

  return (
    <Calendar mode="range" value={twoMonthRange} onChange={setTwoMonthRange} disabled={noPast} cols={2}>
      <CalendarNav showMonthPicker compactYears col={1} />
      <CalendarNav offset={1} monthLabel clear col={1} />
      <CalendarDays col={1} />
      <CalendarDays offset={1} col={1} />
      <CalendarSelectedDates allowClear allowNavigate animated />
    </Calendar>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition

Six-month availability

Use this when
Showing read-only open slots across half a year.
What it demonstrates
Read-only multiple-mode with a 3-column 6-month grid and defaultViewDate.
theme: industrialappearance: compact
read-only6 monthsavailability
Code
import { useMemo } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import { compact } from "@dateforge/react-calendar/appearances";

export function SixmonthAvailabilityExample() {
  const sixMonthDates = useMemo(
    () => [
      new Date(2026, 4, 8),
      new Date(2026, 4, 17),
      new Date(2026, 5, 4),
      new Date(2026, 5, 22),
      new Date(2026, 6, 9),
      new Date(2026, 6, 28),
      new Date(2026, 7, 13),
      new Date(2026, 7, 26),
      new Date(2026, 8, 10),
      new Date(2026, 8, 24),
      new Date(2026, 9, 6),
      new Date(2026, 9, 21),
    ],
    [],
  );

  return (
    <Calendar mode="multiple" value={sixMonthDates} defaultViewDate={new Date("2026-05-01")} readOnly cols={3} appearance={compact}>
      <CalendarNav monthLabel yearLabel col={1} />
      <CalendarNav monthLabel yearLabel offset={1} col={1} />
      <CalendarNav monthLabel yearLabel offset={2} col={1} />
      <CalendarDays col={1} />
      <CalendarDays offset={1} col={1} />
      <CalendarDays offset={2} col={1} />
      <CalendarNav monthLabel yearLabel offset={3} col={1} />
      <CalendarNav monthLabel yearLabel offset={4} col={1} />
      <CalendarNav monthLabel yearLabel offset={5} col={1} />
      <CalendarDays offset={3} col={1} />
      <CalendarDays offset={4} col={1} />
      <CalendarDays offset={5} col={1} /> 
    </Calendar>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition

Delivery slots

Use this when
Letting users pick several non-contiguous delivery dates with capacity.
What it demonstrates
Multiple mode with maxDates, weekend + past disable rule, animated selected list.
theme: mintappearance: soft
multiplecapacity
Code
import { useMemo, useState } from "react";
import { Calendar, createDisabled } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarSelectedDates } from "@dateforge/react-calendar/modules";

export function DeliverySlotsExample() {
  const [deliveryDates, setDeliveryDates] = useState<Date[]>([]);

  const weekdaysOnly = useMemo(() => {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    return createDisabled({ weekends: true, before: today });
  }, []);

  return (
    <Calendar mode="multiple" value={deliveryDates} onChange={setDeliveryDates} maxDates={4} disabled={weekdaysOnly}>
      <CalendarNav compactMonths showYearPicker clear />
      <CalendarDays />
      <CalendarSelectedDates allowClear animated />
    </Calendar>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition

Limited drop window

Use this when
Launch signup with only a handful of valid days.
What it demonstrates
hideOutOfRange + min/maxDate + createDisabled for a tightly bounded picker.
theme: risoappearance: compact
hideOutOfRangedisabled
Code
import { useMemo, useState } from "react";
import { Calendar, createDisabled } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarSelectedDates } from "@dateforge/react-calendar/modules";

export function LimitedDropWindowExample() {
  const [dropDate, setDropDate] = useState<Date | null>(null);

  const dropDisabled = useMemo(
    () =>
      createDisabled({
        dates: [new Date("2026-07-12"), new Date("2026-07-15")],
        weekdays: [0, 6],
      }),
    [],
  );

  return (
    <Calendar
      mode="single"
      value={dropDate}
      onChange={setDropDate}
      defaultViewDate={new Date("2026-07-10")}
      minDate={new Date("2026-07-10")}
      maxDate={new Date("2026-07-18")}
      disabled={dropDisabled}
    >
      <CalendarNav monthLabel yearLabel clear />
      <CalendarDays hideOutOfRange fixedRows={false} />
      <CalendarSelectedDates allowClear animated />
    </Calendar>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
09
00
Composition

Appointment booking

Use this when
Doctor, salon, or restaurant reservations needing date and time in one step.
What it demonstrates
Single mode + CalendarTimeGrid + nav with showTime.
theme: auroraappearance: loft
timeschedulinggradient
Code
import { useMemo, useState } from "react";
import { Calendar, createDisabled } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarSelectedDates, CalendarTimeGrid } from "@dateforge/react-calendar/modules";

export function AppointmentBookingExample() {
  const [appointment, setAppointment] = useState<Date | null>(null);

  const weekdaysOnly = useMemo(() => {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    return createDisabled({ weekends: true, before: today });
  }, []);

  return (
    <Calendar gradient mode="single" value={appointment} onChange={setAppointment} disabled={weekdaysOnly}>
      <CalendarNav showTime showMonthPicker compactYears clear />
      <CalendarDays />
      <CalendarTimeGrid />
      <CalendarSelectedDates allowClear showTime />
    </Calendar>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition

Analytics dashboard

Use this when
Filtering reports by familiar ranges (Today / Last 7 / Quarter).
What it demonstrates
Range mode + CalendarPresets with relative offsets + animated summary.
theme: graphite
rangereports
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarPresets, CalendarSelectedDates } from "@dateforge/react-calendar/modules";

export function AnalyticsDashboardExample() {
  const [reportRange, setReportRange] = useState<{ from: Date | null; to: Date | null }>({ from: null, to: null });

  const analyticsPresets = [
    { label: "Today", value: 0 },
    { label: "Last 7 days", value: -6, range: 6 },
    { label: "Last 30 days", value: -29, range: 29 },
  ];

  return (
    <Calendar mode="range" value={reportRange} onChange={setReportRange}>
      <CalendarNav showMonthPicker compactYears clear />
      <CalendarPresets presets={analyticsPresets} />
      <CalendarDays />
      <CalendarSelectedDates allowClear allowNavigate animated />
    </Calendar>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition

Support quick dates

Use this when
Reminders or follow-ups where "Tomorrow" or "Next Monday" covers most cases.
What it demonstrates
Single mode with custom presets, including dynamic ones via getValue.
theme: mintappearance: soft
single presetssupport
Code
import { useMemo, useState } from "react";
import { Calendar, type PresetEntry } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarPresets, CalendarSelectedDates } from "@dateforge/react-calendar/modules";

export function SupportQuickDatesExample() {
  const [singlePresetDate, setSinglePresetDate] = useState<Date | null>(null);

  const supportPresets = useMemo<PresetEntry[]>(
    () => [
      { label: "Today", value: 0 },
      { label: "Tomorrow", value: 1 },
      { label: "In 3 days", value: 3 },
      {
        id: "next-monday",
        label: "Next Monday",
        getValue: ({ now, isValid }) => {
          const date = new Date(now);
          const delta = (8 - date.getDay()) % 7 || 7;
          date.setDate(date.getDate() + delta);
          return isValid(date) ? date : null;
        },
      },
    ],
    [],
  );

  return (
    <Calendar mode="single" value={singlePresetDate} onChange={setSinglePresetDate}>
      <CalendarNav showMonthPicker compactYears clear />
      <CalendarPresets presets={supportPresets} />
      <CalendarDays />
      <CalendarSelectedDates allowClear allowNavigate animated />
    </Calendar>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
20202029
Composition

Holiday planner

Use this when
Marketing or seasonal planning around fixed and computed holidays.
What it demonstrates
Multiple mode with advanced custom presets (Christmas, Thanksgiving, Black Friday).
theme: snowappearance: compact
advanced presetsholidaysmultiple
Code
import { useMemo, useState } from "react";
import { Calendar, type PresetEntry } from "@dateforge/react-calendar";
import { CalendarDays, CalendarMonthsGrid, CalendarNav, CalendarPresets, CalendarSelectedDates, CalendarYearsGrid } from "@dateforge/react-calendar/modules";

export function HolidayPlannerExample() {
  const [holidayRange, setHolidayRange] = useState<Date[]>([]);

  function nthWeekdayOfMonth(year: number, month: number, weekday: number, occurrence: number) {
    const date = new Date(year, month, 1);
    const delta = (weekday - date.getDay() + 7) % 7;
    date.setDate(1 + delta + (occurrence - 1) * 7);
    return date;
  }

  const holidayPresets = useMemo<PresetEntry[]>(
    () => [
      {
        id: "new-year",
        label: "New Year",
        getValue: ({ now, isValid }) => {
          const year =
            now.getMonth() > 0 || now.getDate() > 1
              ? now.getFullYear() + 1
              : now.getFullYear();
          const date = new Date(year, 0, 1);
          return isValid(date) ? date : null;
        },
      },
      {
        id: "independence-day",
        label: "Independence Day",
        getValue: ({ now, isValid }) => {
          const year =
            now.getMonth() > 6 || (now.getMonth() === 6 && now.getDate() > 4)
              ? now.getFullYear() + 1
              : now.getFullYear();
          const date = new Date(year, 6, 4);
          return isValid(date) ? date : null;
        },
      },
      {
        id: "christmas-day",
        label: "Christmas Day",
        getValue: ({ now, isValid }) => {
          const year =
            now.getMonth() > 11 || (now.getMonth() === 11 && now.getDate() > 25)
              ? now.getFullYear() + 1
              : now.getFullYear();
          const date = new Date(year, 11, 25);
          return isValid(date) ? date : null;
        },
      },
      {
        id: "thanksgiving-day",
        label: "Thanksgiving",
        getValue: ({ now, isValid }) => {
          const year = now.getMonth() > 10 ? now.getFullYear() + 1 : now.getFullYear();
          const date = nthWeekdayOfMonth(year, 10, 4, 4);
          return isValid(date) ? date : null;
        },
      },
      {
        id: "christmas-eve",
        label: "Christmas Eve",
        getValue: ({ now, isValid }) => {
          const year =
            now.getMonth() > 11 || (now.getMonth() === 11 && now.getDate() > 24)
              ? now.getFullYear() + 1
              : now.getFullYear();
          const date = new Date(year, 11, 24);
          return isValid(date) ? date : null;
        },
      },
      {
        id: "black-friday",
        label: "Black Friday",
        getValue: ({ now, isValid }) => {
          const year = now.getMonth() > 10 ? now.getFullYear() + 1 : now.getFullYear();
          const date = nthWeekdayOfMonth(year, 10, 4, 4);
          date.setDate(date.getDate() + 1);
          return isValid(date) ? date : null;
        },
      },
    ],
    [],
  );

  return (
    <Calendar mode="multiple" value={holidayRange} onChange={setHolidayRange} cols={2}>
      <CalendarNav showMonthPicker compactYears clear />
      <CalendarPresets presets={holidayPresets} />
      <CalendarDays />
      <CalendarMonthsGrid col={1} />
      <CalendarYearsGrid col={1} />
      <CalendarSelectedDates allowClear allowNavigate animated />
    </Calendar>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition

Brand theme picker

Use this when
Branded checkout or onboarding where the picker has to match a custom palette.
What it demonstrates
createTheme with full token override (highlight, accent, backdrop, range, etc.).
theme: customappearance: soft
createThemebrand
Code
import { useMemo, useState } from "react";
import { Calendar, createTheme } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarSelectedDates } from "@dateforge/react-calendar/modules";

export function BrandThemePickerExample() {
  const [brandDate, setBrandDate] = useState<Date | null>(null);

  const brandTheme = useMemo(
    () =>
      createTheme({
          highlight: "#f4f96f",
          accent: "#27a925",
          backdrop: "#eae0f1",
          tone:"#ee1818",
          text: "#282626",
          stroke: "#cbd5e1",
          range: "#ccfbf1",
          shadow:'#b9c2cc', 
      }),
    [],
  );

  return (
    <Calendar mode="single" value={brandDate} onChange={setBrandDate} theme={brandTheme}>
      <CalendarNav showMonthPicker compactYears clear />
      <CalendarDays />
      <CalendarSelectedDates allowClear animated />
    </Calendar>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition

Dense product filter

Use this when
Compact dashboards where calendar rhythm needs to match dense data UI.
What it demonstrates
createAppearance with custom radius, spacing, font size, and dayRatio.
theme: graphiteappearance: custom
createAppearancedashboard
Code
import { useMemo, useState } from "react";
import { Calendar, createAppearance } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarSelectedDates } from "@dateforge/react-calendar/modules";

export function DenseProductFilterExample() {
  const [denseRange, setDenseRange] = useState<{ from: Date | null; to: Date | null }>({ from: null, to: null });

  const denseAppearance = useMemo(
    () =>
      createAppearance({
        radius: "5px",
        spacing: "0.42em",
        fontSize: "13px",
        dayRatio: "1 / 0.78",
        transition: "120ms ease",
      }),
    [],
  );

  return (
    <Calendar mode="range" value={denseRange} onChange={setDenseRange} appearance={denseAppearance}>
      <CalendarNav showMonthPicker compactYears clear />
      <CalendarDays />
      <CalendarSelectedDates allowClear animated />
    </Calendar>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition

Vacation request

Use this when
HR-style time off with min and max length rules.
What it demonstrates
Range mode with minRangeDays / maxRangeDays and weekday-only disabled rule.
theme: risoappearance: square
constraintsHR
Code
import { useMemo, useState } from "react";
import { Calendar, createDisabled } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarSelectedDates } from "@dateforge/react-calendar/modules";

export function VacationRequestExample() {
  const [vacationRange, setVacationRange] = useState<{ from: Date | null; to: Date | null }>({ from: null, to: null });

  const weekdaysOnly = useMemo(() => {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    return createDisabled({ weekends: true, before: today });
  }, []);

  return (
    <Calendar
      mode="range"
      value={vacationRange}
      onChange={setVacationRange}
      disabled={weekdaysOnly}
      minRangeDays={2}
      maxRangeDays={21}
    >
      <CalendarNav showMonthPicker compactYears clear />
      <CalendarDays />
      <CalendarSelectedDates allowClear animated />
    </Calendar>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition

Sprint planning

Use this when
Engineering planning around current sprint, next sprint, release week.
What it demonstrates
Range mode with custom-length presets (offset + range).
theme: industrial
presetsplanning
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarPresets, CalendarSelectedDates } from "@dateforge/react-calendar/modules";

export function SprintPlanningExample() {
  const [sprintRange, setSprintRange] = useState<{ from: Date | null; to: Date | null }>({ from: null, to: null });

  const sprintPresets = [
    { label: "Current sprint", value: 0, range: 13 },
    { label: "Next sprint", value: 14, range: 13 },
    { label: "Release week", value: 28, range: 6 },
  ];

  return (
    <Calendar mode="range" value={sprintRange} onChange={setSprintRange}>
      <CalendarNav showMonthPicker compactYears />
      <CalendarPresets presets={sprintPresets} />
      <CalendarDays />
      <CalendarSelectedDates allowClear allowNavigate animated />
    </Calendar>
  );
}
Mo
Di
Mi
Do
Fr
Sa
So
Composition

Invoice due date

Use this when
Billing form where users want to type or pick the date with a strict allowed window.
What it demonstrates
CalendarManualInput paired with the picker, locale, and min/max dates.
theme: snowappearance: soft
manual inputbilling
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarDays, CalendarManualInput, CalendarNav } from "@dateforge/react-calendar/modules";

export function InvoiceDueDateExample() {
  const [manualDate, setManualDate] = useState<Date | null>(null);

  return (
    <Calendar
      mode="single"
      value={manualDate}
      onChange={setManualDate}
      locale="de-DE"
      minDate={new Date("2026-05-01")}
      maxDate={new Date("2026-08-31")}
    >
      <CalendarManualInput allowClear />
      <CalendarNav showMonthPicker compactYears />
      <CalendarDays />
    </Calendar>
  );
}
20182029

Pick a year to browse the archive

Composition

Archive year browser

Use this when
Annual reports, archives, or timeline filters that only need year navigation.
What it demonstrates
Solo CalendarYearsGrid with onYearSelect driving external state.
theme: graphiteappearance: compact
years gridarchive
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarYearsGrid } from "@dateforge/react-calendar/modules";

export function ArchiveYearBrowserExample() {
  const [archiveYear, setArchiveYear] = useState<Date | null>(null);

  return (
    <>
      <Calendar
        mode="single"
        defaultViewDate={new Date("2026-01-01")}
        minDate={new Date("2018-01-01")}
        maxDate={new Date("2030-12-31")}
      >
        <CalendarYearsGrid
          yearsPerPage={12}
          onYearSelect={(date) => setArchiveYear(date)}
        />
      </Calendar>
      {archiveYear && <p>Browsing archive · {archiveYear.getFullYear()}</p>}
    </>
  );
}

Pick a month to plan the campaign

Composition

Campaign month picker

Use this when
Lightweight season, campaign, or billing-period selectors.
What it demonstrates
Solo CalendarMonthsGrid with onMonthSelect driving external state.
theme: temporalappearance: soft
months gridcampaign
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarMonthsGrid } from "@dateforge/react-calendar/modules";

export function CampaignMonthPickerExample() {
  const [campaignMonth, setCampaignMonth] = useState<Date | null>(null);

  return (
    <>
      <Calendar
        mode="single"
        defaultViewDate={new Date("2026-05-01")}
        minDate={new Date("2026-01-01")}
        maxDate={new Date("2026-12-31")}
        gradient
      >
        <CalendarMonthsGrid
          short
          onMonthSelect={(date) => setCampaignMonth(date)}
        />
      </Calendar>
      {campaignMonth && (
        <p>
          Campaign ·{" "}
          {campaignMonth.toLocaleString("en-US", { month: "long", year: "numeric" })}
        </p>
      )}
    </>
  );
}
18
20

Pick a time slot

Composition

Time slot picker

Use this when
Slot pickers, reminders, or any flow where the date is fixed and only time matters.
What it demonstrates
Solo CalendarTimeGrid with timeStep={{ minute: 10 }} for snapped slots.
theme: auroraappearance: loft
time gridslots
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarTimeGrid } from "@dateforge/react-calendar/modules";

export function TimeSlotPickerExample() {
  const [meetingTime, setMeetingTime] = useState<Date | null>(null);

  return (
    <>
      <Calendar
        mode="single"
        value={meetingTime}
        onChange={setMeetingTime}
        timeStep={{ minute: 10 }}
      >
        <CalendarTimeGrid />
      </Calendar>
      {meetingTime && (
        <p>
          Slot ·{" "}
          {meetingTime.toLocaleTimeString("en-US", {
            hour: "2-digit",
            minute: "2-digit",
          })}
        </p>
      )}
    </>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
06
24
Same moment around the world
  • New York
  • London
  • Berlin
  • Tokyo
Composition

Global meeting time

Use this when
Scheduling one slot that teammates in different time zones can read at a glance.
What it demonstrates
timeZone + hour12 on the calendar, with the same instant rendered in four cities.
theme: auroraappearance: loft
time zonehour12
Code
import { useMemo, useState } from "react";
import { Calendar, createDisabled } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarSelectedDates, CalendarTimeGrid } from "@dateforge/react-calendar/modules";

export function GlobalMeetingTimeExample() {
  const ZONES = [
    { city: "New York", tz: "America/New_York" },
    { city: "London", tz: "Europe/London" },
    { city: "Berlin", tz: "Europe/Berlin" },
    { city: "Tokyo", tz: "Asia/Tokyo" },
  ];

  const [globalMeeting, setGlobalMeeting] = useState<Date | null>(null);

  const noPast = useMemo(() => {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    return createDisabled({ before: today });
  }, []);

  return (
    <Calendar
      mode="single"
      value={globalMeeting}
      onChange={setGlobalMeeting}
      timeZone="America/New_York"
      hour12
      disabled={noPast}
    >
      <CalendarNav showTime showMonthPicker compactYears clear />
      <CalendarDays />
      <CalendarTimeGrid />
    </Calendar>

    {globalMeeting && (
      <ul>
        {ZONES.map((z) => (
          <li key={z.tz}>
            <span>{z.city}</span>
            <span>
              {globalMeeting.toLocaleString("en-US", {
                timeZone: z.tz,
                weekday: "short",
                month: "short",
                day: "numeric",
                hour: "2-digit",
                minute: "2-digit",
                hour12: true,
              })}
            </span>
          </li>
        ))}
      </ul>
    )}
  );
}
1994
Jun
14Jun
Composition

Profile birthday

Use this when
Older dates where jumping years and months matters more than a month grid.
What it demonstrates
Track-based UI (CalendarYearsTrack, CalendarMonthsTrack, CalendarDaysTrack).
theme: midnightappearance: bubble
tracksprofile
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarDaysTrack, CalendarMonthsTrack, CalendarSelectedDates, CalendarYearsTrack } from "@dateforge/react-calendar/modules";
import { bubble } from "@dateforge/react-calendar/appearances";

export function ProfileBirthdayExample() {
  const [birthday, setBirthday] = useState<Date | null>(new Date(1994, 5, 14));

  return (
    <Calendar mode="single" value={birthday} onChange={setBirthday} appearance={bubble}>
      <CalendarYearsTrack />
      <CalendarMonthsTrack short />
      <CalendarDaysTrack showMonthLabel />
      <CalendarSelectedDates allowClear />
    </Calendar>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition

Blackout calendar

Use this when
Operations calendars with weekends, maintenance windows, and exact blackout dates.
What it demonstrates
Range mode with composite createDisabled (weekends + before + ranges + dates).
theme: graphiteappearance: compact
disabledoperations
Code
import { useMemo, useState } from "react";
import { Calendar, createDisabled } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarSelectedDates } from "@dateforge/react-calendar/modules";

export function BlackoutCalendarExample() {
  const [blackoutRange, setBlackoutRange] = useState<{ from: Date | null; to: Date | null }>({ from: null, to: null });

  const blackout = createDisabled({
    weekends: true,
    before: new Date(),
    ranges: [{ from: new Date("2026-06-10"), to: new Date("2026-06-14") }],
  });

  return (
    <Calendar mode="range" value={blackoutRange} onChange={setBlackoutRange} disabled={blackout}>
      <CalendarNav compactMonths compactYears clear />
      <CalendarDays />
      <CalendarSelectedDates allowClear animated />
    </Calendar>
  );
}
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition

Launch day

Use this when
Locked launches, archive screens, or confirmed bookings.
What it demonstrates
readOnly flag plus allowNavigate on the selected dates display.
theme: snowappearance: soft
read-onlystatus
Code
import { Calendar } from "@dateforge/react-calendar";
import { CalendarDays, CalendarNav, CalendarSelectedDates } from "@dateforge/react-calendar/modules";

export function LaunchDayExample() {
  const launchDate = new Date(2026, 8, 9);

  return (
    <Calendar mode="single" value={launchDate} readOnly>
      <CalendarNav monthLabel yearLabel />
      <CalendarDays />
      <CalendarSelectedDates allowNavigate animated />
    </Calendar>
  );
}