Component reference
Scheduler
Review and create events in a weekly schedule.
Preview
Live previewOptional six-digit hex. Clear to restore the preset. Check contrast with your brand color.
Changes apply to this preview only.
Use arrow keys to navigate dates and times, Home and End to reach row boundaries, Control Home and Control End for the whole grid. Enter activates a slot. F2 explores actions inside a cell; Escape returns to the cell.
Design review
Tue, Oct 20, 10:00 AM – Tue, Oct 20, 11:30 AM
The event button carries its weekday, date and time range as an accessible label. Overlapping events share the day column without covering each other.
Create from a slot
Click an empty hour to receive a slot payload.
No slot selected. The handler receives the local date, the slot start and its end.
Width adapts to the available space
"use client";
import { useState } from "react";
import {
type PimoluSchedulerEvent,
type PimoluSchedulerSlot,
Scheduler,
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
Badge
} from "@pimolu/react";
const DEMO_WEEK = new Date(2026, 9, 20);
const teamEvents: PimoluSchedulerEvent[] = [
{
id: "standup",
title: "Team stand-up",
start: new Date(2026, 9, 19, 9, 0),
end: new Date(2026, 9, 19, 9, 30),
color: "#0ea5e9",
},
{
id: "design-review",
title: "Design review",
start: new Date(2026, 9, 20, 10, 0),
end: new Date(2026, 9, 20, 11, 30),
color: "#4f46e5",
},
{
id: "customer-call",
title: "Customer call",
start: new Date(2026, 9, 20, 10, 30),
end: new Date(2026, 9, 20, 11, 45),
color: "#d97706",
},
{
id: "planning",
title: "Sprint planning",
start: new Date(2026, 9, 21, 14, 0),
end: new Date(2026, 9, 21, 15, 30),
color: "#16a34a",
},
{
id: "release",
title: "Release window",
start: new Date(2026, 9, 22),
end: new Date(2026, 9, 23),
color: "#dc2626",
allDay: true,
},
{
id: "retro",
title: "Sprint retro",
start: new Date(2026, 9, 23, 16, 0),
end: new Date(2026, 9, 23, 17, 0),
color: "#7c3aed",
},
];
const timeFormat = new Intl.DateTimeFormat("en-US", {
weekday: "short",
month: "short",
day: "numeric",
hour: "numeric",
minute: "2-digit",
});
function formatTimeRange(event: PimoluSchedulerEvent) {
if(event.allDay) {
return "All day";
}
return `${timeFormat.format(event.start)} – ${timeFormat.format(event.end)}`;
}
function WeekSchedulerExample() {
const [date, setDate] = useState(DEMO_WEEK);
const [selected, setSelected] = useState<PimoluSchedulerEvent | null>(teamEvents[1]);
const [lastSlot, setLastSlot] = useState<PimoluSchedulerSlot | null>(null);
return (
<div className="grid gap-5 min-w-0">
<Scheduler
aria-label="Product team week"
events={teamEvents}
date={date}
onDateChange={setDate}
onEventClick={setSelected}
onSlotClick={setLastSlot}
weekStartsOn={1}
minTime={8 * 60}
maxTime={19 * 60}
/>
<div
className="grid grid-cols-[repeat(auto-fit,minmax(min(100%,280px),1fr))] gap-6 min-w-0"
>
<Card>
<CardHeader>
<CardTitle>
{selected?.title ?? "Select an event"}
</CardTitle>
<CardDescription>
{
selected
? formatTimeRange(selected)
: "Click an event to inspect its details."
}
</CardDescription>
</CardHeader>
<CardContent className="grid gap-5 min-w-0">
{
selected
? (<>
<div className="flex flex-wrap items-center gap-3 min-w-0">
<Badge variant="neutral">
{
selected.allDay
? "All day"
: "Timed event"
}
</Badge>
<Badge variant="primary">
{selected.id}
</Badge>
</div>
<p className="text-sm text-muted">
The event button carries its weekday, date and time range as an
accessible label. Overlapping events share the day column
without covering each other.
</p>
</>)
: (<p className="text-sm text-muted">No event selected yet.</p>)
}
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Create from a slot</CardTitle>
<CardDescription>Click an empty hour to receive a slot payload.</CardDescription>
</CardHeader>
<CardContent className="grid gap-5 min-w-0">
{
lastSlot
? (<>
<p className="text-sm text-muted">
{
new Intl.DateTimeFormat("en-US", {
weekday: "long",
month: "long",
day: "numeric",
}).format(lastSlot.date)
}
</p>
<p>
{
new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "2-digit",
}).format(lastSlot.start)
}{" "}
–{" "}
{
new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "2-digit",
}).format(lastSlot.end)
}
</p>
</>)
: (<p className="text-sm text-muted">
No slot selected. The handler receives the local date, the slot
start and its end.
</p>)
}
</CardContent>
</Card>
</div>
</div>
);
}
export function DemoExample() {
return (<WeekSchedulerExample />);
}More examples
Different configurations and compositions using the real Pimolu API. Each preview runs independently and follows the site appearance.
A focused workday
A short agenda with one event and a compact working-hours window.
Keyboard navigation
Tab enters one cell. Arrow keys move across days and hours; Home/End reach row edges. F2 enters cell actions and Escape returns to the cell.
Read-only schedule
Cells remain keyboard navigable even without an add-event handler.
Usage
Keep event ids stable and decide timezone, overlap and persistence rules in the application.
API reference
Generated from the public TypeScript declarations. Native HTML attributes are inherited where the component extends them; this reference includes Pimolu props and selected common native attributes.
PimoluSchedulerEvent
Type source| Name | Type | Default | Description |
|---|---|---|---|
idRequired | string | — | Stable identifier, also used as the React key. |
titleRequired | string | — | Visible event title. |
startRequired | Date | — | Start instant. Events spanning several days are split per day. |
endRequired | Date | — | End instant. Ignored for all-day events. |
color | string | undefined | — | Optional accent colour used for the event background and border. |
allDay | boolean | undefined | — | All-day events are rendered in a dedicated row above the time grid. |
idRequiredstringNo default extracted.
Stable identifier, also used as the React key.
titleRequiredstringNo default extracted.
Visible event title.
startRequiredDateNo default extracted.
Start instant. Events spanning several days are split per day.
endRequiredDateNo default extracted.
End instant. Ignored for all-day events.
colorstring | undefinedNo default extracted.
Optional accent colour used for the event background and border.
allDayboolean | undefinedNo default extracted.
All-day events are rendered in a dedicated row above the time grid.
PimoluSchedulerSlot
Type source| Name | Type | Default | Description |
|---|---|---|---|
dateRequired | Date | — | The clicked day, at local midnight. |
startRequired | Date | — | Start of the slot (whole hour). |
endRequired | Date | — | End of the slot (start + one hour). |
dateRequiredDateNo default extracted.
The clicked day, at local midnight.
startRequiredDateNo default extracted.
Start of the slot (whole hour).
endRequiredDateNo default extracted.
End of the slot (start + one hour).
PimoluSchedulerProps
Type source| Name | Type | Default | Description |
|---|---|---|---|
eventsRequired | readonly PimoluSchedulerEvent[] | — | Events to display. Events outside the visible days are ignored. |
date | Date | undefined | — | Controlled anchor date. The visible week/day is derived from it. |
defaultDate | Date | undefined | today | Initial anchor date when uncontrolled. Defaults to today. |
onDateChange | ((date: Date) => void) | undefined | — | Called with the next anchor date after navigation, or when "Today" is pressed. |
view | PimoluSchedulerView | undefined | — | Controlled view. |
defaultView | PimoluSchedulerView | undefined | "week" | Initial view when uncontrolled. Defaults to "week". |
onViewChange | ((view: PimoluSchedulerView) => void) | undefined | — | Called when the Week/Day toggle changes. |
weekStartsOn | 0 | 1 | undefined | 0 | First day of the week: 0 = Sunday, 1 = Monday. Defaults to 0. |
minTime | number | undefined | 0 | First visible hour, as minutes from midnight. Defaults to 0. Values are rounded down to the previous hour. |
maxTime | number | undefined | 1440 | Last visible hour, as minutes from midnight. Defaults to 1440. Values are rounded up to the next hour. |
locale | string | undefined | "en-US" | BCP 47 locale used for all date and time labels. Defaults to "en-US". |
showCurrentTime | boolean | undefined | true | Shows a line for the current time on today's column. Defaults to true. |
hourHeight | number | undefined | 64 | Height of one hour row, in pixels. Defaults to 64. |
onEventClick | ((event: PimoluSchedulerEvent) => void) | undefined | — | Called when an event button is activated. |
onSlotClick | ((slot: PimoluSchedulerSlot) => void) | undefined | — | Called when an empty time slot is activated. |
className | string | undefined | — | Class applied to the outer scheduler. |
aria-label | string | undefined | "Schedule" | Accessible name of the time grid. Defaults to "Schedule". |
eventsRequiredreadonly PimoluSchedulerEvent[]No default extracted.
Events to display. Events outside the visible days are ignored.
dateDate | undefinedNo default extracted.
Controlled anchor date. The visible week/day is derived from it.
defaultDateDate | undefinedDefault: today
Initial anchor date when uncontrolled. Defaults to today.
onDateChange((date: Date) => void) | undefinedNo default extracted.
Called with the next anchor date after navigation, or when "Today" is pressed.
viewPimoluSchedulerView | undefinedNo default extracted.
Controlled view.
defaultViewPimoluSchedulerView | undefinedDefault: "week"
Initial view when uncontrolled. Defaults to "week".
onViewChange((view: PimoluSchedulerView) => void) | undefinedNo default extracted.
Called when the Week/Day toggle changes.
weekStartsOn0 | 1 | undefinedDefault: 0
First day of the week: 0 = Sunday, 1 = Monday. Defaults to 0.
minTimenumber | undefinedDefault: 0
First visible hour, as minutes from midnight. Defaults to 0. Values are rounded down to the previous hour.
maxTimenumber | undefinedDefault: 1440
Last visible hour, as minutes from midnight. Defaults to 1440. Values are rounded up to the next hour.
localestring | undefinedDefault: "en-US"
BCP 47 locale used for all date and time labels. Defaults to "en-US".
showCurrentTimeboolean | undefinedDefault: true
Shows a line for the current time on today's column. Defaults to true.
hourHeightnumber | undefinedDefault: 64
Height of one hour row, in pixels. Defaults to 64.
onEventClick((event: PimoluSchedulerEvent) => void) | undefinedNo default extracted.
Called when an event button is activated.
onSlotClick((slot: PimoluSchedulerSlot) => void) | undefinedNo default extracted.
Called when an empty time slot is activated.
classNamestring | undefinedNo default extracted.
Class applied to the outer scheduler.
aria-labelstring | undefinedDefault: "Schedule"
Accessible name of the time grid. Defaults to "Schedule".
Accessibility
- The grid has one Tab entry. Arrows navigate dates and hours (including RTL), Home/End reach row edges, Control+Home/End reach grid edges. Enter activates a slot; F2 enters cell actions and Escape returns to the cell. Timed event buttons remain reachable separately.
- Check event focus, date controls and keyboard alternatives to pointer-only scheduling.