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-calendarMon
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, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
export function TheBasicsExample() {
const [basicDate, setBasicDate] = useState<Date | null>(new Date());
return (
<Calendar mode="single" value={basicDate} onChange={setBasicDate}>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
</CalendarToolbar>
<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, quick-stay presets, a nights counter via CalendarInfo, and an animated summary.
appearance: soft
rangebookingpresets
Code
import { useMemo, useState } from "react";
import { Calendar, basicPresets, createDisabled } from "@dateforge/react-calendar";
import { CalendarDays, CalendarPresets, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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} appearance={soft}>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
<CalendarToolbarHome />
<CalendarToolbarClear />
</CalendarToolbar>
<CalendarDays />
<CalendarPresets presets={basicPresets.slice(4, 9)} />
<CalendarInfo showSummary rangeStyle="duration" />
<CalendarSelectedDates allowClear allowNavigate animated />
</Calendar>
);
}Jun
Jun
5
5
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
rangetracksmobile
Code
import { useMemo, useState } from "react";
import { Calendar, createDisabled } from "@dateforge/react-calendar";
import { CalendarDaysTrack, CalendarMonthsTrack, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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}>
<CalendarToolbar col={2}>
<CalendarToolbarLabel label="Departure" />
<CalendarToolbarPrev />
<CalendarToolbarMonthLabel />
<CalendarToolbarYearLabel />
<CalendarToolbarLabel label="Return" />
<CalendarToolbarMonthLabel offset={1} />
<CalendarToolbarYearLabel offset={1} />
<CalendarToolbarNext />
<CalendarToolbarClear />
</CalendarToolbar>
<CalendarMonthsTrack bound="from" short />
<CalendarDaysTrack bound="from" showMonthLabel />
<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 twoCalendarDays(offset 0 and 1) and one continuous range value.
theme: snowappearance: soft
range2 monthsdesktop
Code
import { useMemo, useState } from "react";
import { Calendar, createDisabled } from "@dateforge/react-calendar";
import { CalendarDays, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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}>
<CalendarToolbar col={2}>
<CalendarToolbarPrev />
<CalendarToolbarMonthLabel />
<CalendarToolbarYearLabel />
<CalendarToolbarMonthLabel offset={1} />
<CalendarToolbarYearLabel offset={1} />
<CalendarToolbarNext />
</CalendarToolbar>
<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, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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}>
<CalendarToolbar col={1}>
<CalendarToolbarMonthLabel />
<CalendarToolbarYearLabel />
</CalendarToolbar>
<CalendarToolbar col={1} offset={1}>
<CalendarToolbarMonthLabel />
<CalendarToolbarYearLabel />
</CalendarToolbar>
<CalendarToolbar col={1} offset={2}>
<CalendarToolbarMonthLabel />
<CalendarToolbarYearLabel />
</CalendarToolbar>
<CalendarDays col={1} />
<CalendarDays offset={1} col={1} />
<CalendarDays offset={2} col={1} />
<CalendarToolbar col={1} offset={3}>
<CalendarToolbarMonthLabel />
<CalendarToolbarYearLabel />
</CalendarToolbar>
<CalendarToolbar col={1} offset={4}>
<CalendarToolbarMonthLabel />
<CalendarToolbarYearLabel />
</CalendarToolbar>
<CalendarToolbar col={1} offset={5}>
<CalendarToolbarMonthLabel />
<CalendarToolbarYearLabel />
</CalendarToolbar>
<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, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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}>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger compact />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger />
</CalendarToolbar>
<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+createDisabledfor a tightly bounded picker.
theme: risoappearance: compact
singlehideOutOfRangedisabledclock
Code
import { useMemo, useState } from "react";
import { Calendar, createDisabled } from "@dateforge/react-calendar";
import { CalendarDays, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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}
>
<CalendarToolbar>
<CalendarToolbarMonthLabel />
<CalendarToolbarYearLabel />
<CalendarToolbarClock />
</CalendarToolbar>
<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 +
CalendarTimeWheel+ nav withshowTime.
theme: auroraappearance: loft
singletimescheduling
Code
import { useMemo, useState } from "react";
import { Calendar, createDisabled } from "@dateforge/react-calendar";
import { CalendarDays, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import { CalendarTimeWheel } from "@dateforge/react-calendar/modules/time";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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}>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
<CalendarToolbarClear />
</CalendarToolbar>
<CalendarDays />
<CalendarTimeWheel />
<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 +
CalendarPresetswith relative offsets + animated summary.
theme: graphite
rangepresetsreports
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarDays, CalendarPresets, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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}>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
<CalendarToolbarClear />
</CalendarToolbar>
<CalendarDays />
<CalendarPresets presets={analyticsPresets} />
<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
singlepresetssupport
Code
import { useMemo, useState } from "react";
import { Calendar, type PresetEntry } from "@dateforge/react-calendar";
import { CalendarDays, CalendarPresets, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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}>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
<CalendarToolbarClear />
</CalendarToolbar>
<CalendarDays />
<CalendarPresets presets={supportPresets} />
<CalendarSelectedDates allowClear allowNavigate animated />
</Calendar>
);
}Mon
Tue
Wed
Thu
Fri
Sat
Sun
2020–2029
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
multiplepresetsholidays
Code
import { useMemo, useState } from "react";
import { Calendar, type PresetEntry } from "@dateforge/react-calendar";
import { CalendarDays, CalendarMonthsGrid, CalendarPresets, CalendarSelectedDates, CalendarYearsGrid } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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}>
<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 in both light and dark.
- What it demonstrates
createThemewith shared tokens pluslight/darkvariants, and a built-in theme toggle to flip between them.
theme: customappearance: soft
singlecreateThemebrand
Code
import { useMemo, useState } from "react";
import { Calendar, createTheme } from "@dateforge/react-calendar";
import { CalendarDays, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
export function BrandThemePickerExample() {
const [brandDate, setBrandDate] = useState<Date | null>(null);
// Shared tokens apply to both variants; light/dark override per mode.
const brandTheme = useMemo(
() =>
createTheme({
highlight: "#7c3aed",
accent: "#ede9fe",
range: "#ddd6fe",
weekend: "#db2777",
light: { backdrop: "#faf5ff", tone: "#f3e8ff", text: "#3b0764", stroke: "#e9d5ff" },
dark: { backdrop: "#1a0b2e", tone: "#2e1065", text: "#f5f3ff", stroke: "#4c1d95" },
}),
[],
);
return (
<Calendar mode="single" value={brandDate} onChange={setBrandDate} theme={brandTheme}>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
<CalendarToolbarThemeToggle />
</CalendarToolbar>
<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
createAppearancewith custom radius, spacing, font size, anddayRatio.
theme: graphiteappearance: custom
rangecreateAppearancedashboard
Code
import { useMemo, useState } from "react";
import { Calendar, createAppearance } from "@dateforge/react-calendar";
import { CalendarDays, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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}>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
<CalendarToolbarClear />
</CalendarToolbar>
<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, weekday-only rule, andCalendarInfoshowing the duration as the user drags.
theme: risoappearance: square
rangeconstraintsHR
Code
import { useMemo, useState } from "react";
import { Calendar, createDisabled } from "@dateforge/react-calendar";
import { CalendarDays, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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}
>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
<CalendarToolbarClear />
</CalendarToolbar>
<CalendarDays />
<CalendarInfo showSummary rangeStyle="duration" />
<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
rangepresetsplanning
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarDays, CalendarPresets, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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}>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
</CalendarToolbar>
<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
CalendarManualInputpaired with the picker,locale, and min/max dates.
theme: snowappearance: soft
singlemanual inputbilling
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarDays, CalendarManualInput } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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")}
>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
</CalendarToolbar>
<CalendarDays />
<CalendarManualInput allowClear />
</Calendar>
);
}2018–2029
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
CalendarYearsGridwithonYearSelectdriving 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: 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
CalendarMonthsGridwithonMonthSelectdriving 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: Date) => setCampaignMonth(date)}
/>
</Calendar>
{campaignMonth && (
<p>
Campaign ·{" "}
{campaignMonth.toLocaleString("en-US", { month: "long", year: "numeric" })}
</p>
)}
</>
);
}17
40
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
CalendarTimeWheelwithtimeStep={{ minute: 10 }}for snapped slots.
theme: auroraappearance: loft
timeslots
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarTimeWheel } from "@dateforge/react-calendar/modules/time";
export function TimeSlotPickerExample() {
const [meetingTime, setMeetingTime] = useState<Date | null>(null);
return (
<>
<Calendar
mode="single"
value={meetingTime}
onChange={setMeetingTime}
timeStep={{ minute: 10 }}
>
<CalendarTimeWheel />
</Calendar>
{meetingTime && (
<p>
Slot ·{" "}
{meetingTime.toLocaleTimeString("en-US", {
hour: "2-digit",
minute: "2-digit",
})}
</p>
)}
</>
);
}Mon
Tue
Wed
Thu
Fri
Sat
Sun
05
43
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+hour12on the calendar, with the same instant rendered in four cities.
theme: auroraappearance: loft
singletime zonehour12
Code
import { useMemo, useState } from "react";
import { Calendar, createDisabled } from "@dateforge/react-calendar";
import { CalendarDays, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import { CalendarTimeWheel } from "@dateforge/react-calendar/modules/time";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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}
>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
<CalendarToolbarClear />
</CalendarToolbar>
<CalendarDays />
<CalendarTimeWheel />
</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
singletracksbirthday
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
rangedisabledoperations
Code
import { useMemo, useState } from "react";
import { Calendar, createDisabled } from "@dateforge/react-calendar";
import { CalendarDays, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
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}>
<CalendarToolbar>
<CalendarToolbarMonthTrigger compact />
<CalendarToolbarPrev unit="year" />
<CalendarToolbarYearTrigger />
<CalendarToolbarNext unit="year" />
<CalendarToolbarHome />
</CalendarToolbar>
<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
readOnlyflag plusallowNavigateon the selected dates display.
theme: snowappearance: soft
read-onlystatus
Code
import { Calendar } from "@dateforge/react-calendar";
import { CalendarDays, CalendarSelectedDates } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
export function LaunchDayExample() {
const launchDate = new Date(2026, 8, 9);
return (
<Calendar mode="single" value={launchDate} readOnly>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthLabel />
<CalendarToolbarNext />
<CalendarToolbarYearLabel />
</CalendarToolbar>
<CalendarDays />
<CalendarSelectedDates allowNavigate animated />
</Calendar>
);
}June
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition
Month wheel + day grid
- Use this when
- Compact pickers where month is spun via drum, day selected via grid.
- What it demonstrates
cols={2}, arrows navigate by year, wheel handles month, YearTrigger compact at right.
theme: temporalappearance: soft
singlewheel2 cols
Code
import { Calendar } from "@dateforge/react-calendar";
export function MonthWheelDayGridExample() {
return (
<Calendar mode="single" value={date} onChange={setDate} cols={2}>
<CalendarToolbar>
<CalendarToolbarPrev unit="year" />
<CalendarToolbarYearTrigger />
<CalendarToolbarNext unit="year" />
</CalendarToolbar>
<CalendarMonthsWheel col={1} showLabel />
<CalendarDays col={1} />
</Calendar>
);
}Mon
Tue
Wed
Thu
Fri
Sat
Sun
Tuesday, May 26, 2026, Waxing gibbous
Wednesday, May 27, 2026, Waxing gibbous
Thursday, May 28, 2026, Waxing gibbous
Friday, May 29, 2026, Waxing gibbous
Saturday, May 30, 2026, Full moon
Sunday, May 31, 2026, Full moon
Monday, June 1, 2026, Full moon
Tuesday, June 2, 2026, Full moon
Wednesday, June 3, 2026, Waning gibbous
Thursday, June 4, 2026, Waning gibbous
Friday, June 5, 2026, Waning gibbous
Saturday, June 6, 2026, Waning gibbous
Sunday, June 7, 2026, Last quarter
Monday, June 8, 2026, Last quarter
Tuesday, June 9, 2026, Last quarter
Wednesday, June 10, 2026, Waning crescent
Thursday, June 11, 2026, Waning crescent
Friday, June 12, 2026, Waning crescent
Saturday, June 13, 2026, Waning crescent
Sunday, June 14, 2026, New moon
Monday, June 15, 2026, New moon
Composition
Lunar phase strip
- Use this when
- Astrology apps, farming calendars, tide trackers, or any domain where lunar phase is meaningful.
- What it demonstrates
CalendarLunarbelow the day grid — display-only, no interaction.
theme: nebulaappearance: soft
singlelunar
Code
import { Calendar } from "@dateforge/react-calendar";
export function LunarPhaseStripExample() {
import { CalendarLunar } from "@dateforge/react-calendar/modules/lunar";
return (
<Calendar mode="single" value={date} onChange={setDate}>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
</CalendarToolbar>
<CalendarDays />
<CalendarLunar />
</Calendar>
);
}Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition
Weather forecast
- Use this when
- Trip planners or weather apps where each day shows an at-a-glance condition.
- What it demonstrates
CalendarDays renderDayreturning a custom cell — day number plus a per-day weather emoji.
theme: auroraappearance: soft
renderDaycustom cellcustom calendar
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarDays } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
export function WeatherForecastExample() {
// Deterministic per-day value so each date always looks the same.
const seededRandom = (d: Date) => {
const seed = d.getFullYear() * 10000 + (d.getMonth() + 1) * 100 + d.getDate();
const x = Math.sin(seed) * 10000;
return x - Math.floor(x);
};
const WEATHER_ICONS = ["☀️", "⛅", "☁️", "🌧", "⛈", "❄️"];
const weatherFor = (d: Date) =>
WEATHER_ICONS[Math.floor(seededRandom(d) * WEATHER_ICONS.length)];
return (
<Calendar mode="single" value={date} onChange={setDate}>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
</CalendarToolbar>
<CalendarDays
renderDay={(d, state) => {
if (state.isOtherMonth) return <span>{d.getDate()}</span>;
return (
<span style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 2, lineHeight: 1.1 }}>
<span style={{ fontSize: 13 }}>{d.getDate()}</span>
<span aria-hidden style={{ fontSize: 13 }}>{weatherFor(d)}</span>
</span>
);
}}
/>
</Calendar>
);
}Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition
Activity heatmap
- Use this when
- Contribution graphs, habit trackers, or any view where each day carries an intensity.
- What it demonstrates
renderDaywith an absolute-positioned fill behind the number to tint each cell.
theme: mintappearance: soft
renderDayheatmapcustom calendar
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarDays } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
export function ActivityHeatmapExample() {
const seededRandom = (d: Date) => {
const seed = d.getFullYear() * 10000 + (d.getMonth() + 1) * 100 + d.getDate();
const x = Math.sin(seed) * 10000;
return x - Math.floor(x);
};
const heatColor = (intensity: number) => {
const alpha = Math.min(0.85, 0.08 + intensity * 0.7);
return `rgba(34, 139, 60, ${alpha})`;
};
return (
<Calendar mode="single" value={date} onChange={setDate}>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
</CalendarToolbar>
<CalendarDays
renderDay={(d, state) => {
if (state.isOtherMonth) return <span>{d.getDate()}</span>;
const intensity = seededRandom(d);
return (
<>
{/* Absolute fill overrides the .activeItem background so the
heatmap color wins on every appearance / border-radius. */}
<span aria-hidden style={{ position: "absolute", inset: 0, background: heatColor(intensity), borderRadius: "inherit" }} />
<span style={{ position: "relative", fontSize: 13 }}>{d.getDate()}</span>
</>
);
}}
/>
</Calendar>
);
}Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition
Ticket prices
- Use this when
- Flight or event booking where users want to spot the cheapest day to buy.
- What it demonstrates
renderDayshowing a derived price under each day — green when cheap, red when pricey.
theme: temporalappearance: compact
renderDaypricingcustom calendar
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarDays } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
export function TicketPricesExample() {
const seededRandom = (d: Date) => {
const seed = d.getFullYear() * 10000 + (d.getMonth() + 1) * 100 + d.getDate();
const x = Math.sin(seed) * 10000;
return x - Math.floor(x);
};
const priceFor = (d: Date) => {
const dow = d.getDay();
const isWeekend = dow === 0 || dow === 6;
return Math.round(79 + seededRandom(d) * 220 + (isWeekend ? 60 : 0));
};
return (
<Calendar mode="single" value={date} onChange={setDate}>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
</CalendarToolbar>
<CalendarDays
renderDay={(d, state) => {
if (state.isOtherMonth) return <span>{d.getDate()}</span>;
const price = priceFor(d);
const isCheap = price < 140;
return (
<span style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 2, lineHeight: 1.1 }}>
<span style={{ fontSize: 13 }}>{d.getDate()}</span>
<span aria-hidden style={{ fontSize: 10, fontWeight: 600, color: isCheap ? "#15803d" : "#b91c1c" }}>
${price}
</span>
</span>
);
}}
/>
</Calendar>
);
}Mon
Tue
Wed
Thu
Fri
Sat
Sun
Composition
Event dots
- Use this when
- Schedules or agendas that mark how many events fall on a given day.
- What it demonstrates
renderDayrendering 1–3 dots under days that have events.
theme: nebulaappearance: soft
renderDayeventscustom calendar
Code
import { useState } from "react";
import { Calendar } from "@dateforge/react-calendar";
import { CalendarDays } from "@dateforge/react-calendar/modules";
import {
CalendarToolbar,
CalendarToolbarPrev,
CalendarToolbarMonthTrigger,
CalendarToolbarNext,
CalendarToolbarYearTrigger,
} from "@dateforge/react-calendar/modules/toolbar";
export function EventDotsExample() {
const seededRandom = (d: Date) => {
const seed = d.getFullYear() * 10000 + (d.getMonth() + 1) * 100 + d.getDate();
const x = Math.sin(seed) * 10000;
return x - Math.floor(x);
};
const EVENT_DAYS = new Set([3, 7, 14, 18, 22, 27]);
const eventCount = (d: Date) => {
if (!EVENT_DAYS.has(d.getDate())) return 0;
return 1 + Math.floor(seededRandom(d) * 3);
};
return (
<Calendar mode="single" value={date} onChange={setDate}>
<CalendarToolbar>
<CalendarToolbarPrev />
<CalendarToolbarMonthTrigger />
<CalendarToolbarNext />
<CalendarToolbarYearTrigger compact />
</CalendarToolbar>
<CalendarDays
renderDay={(d, state) => {
if (state.isOtherMonth) return <span>{d.getDate()}</span>;
const count = eventCount(d);
return (
<span style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 2, lineHeight: 1.1 }}>
<span style={{ fontSize: 13 }}>{d.getDate()}</span>
<span aria-hidden style={{ display: "flex", gap: 2, height: 4 }}>
{Array.from({ length: count }, (_, i) => (
<span key={i} style={{ width: 4, height: 4, borderRadius: "50%", background: "currentColor", opacity: 0.7 }} />
))}
</span>
</span>
);
}}
/>
</Calendar>
);
}