Skip to content

Schedule

Read-only schedule shell for day, week, month, and list views.

August 2026

Sun

Mon

Tue

Wed

Thu

Fri

Sat

26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<ScheduleStory view={createScheduleMonthlyView()} />

August 2026

UTC
Customer summitDesign reviewPlanning offsite
8 AM
9 AM
10 AM
Team syncRoom 410:00 AM - 11:00 AM
11 AM
12 PM
1 PM
2 PM
Prototype critique2:00 PM - 3:00 PM
3 PM
4 PM
5 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<ScheduleStory
events={weekEvents}
view={createScheduleWeeklyView({maxHour: 18, minHour: 8})}
/>

August 2026

UTC
Customer summitDesign reviewPlanning offsite
8 AM
9 AM
10 AM
Team syncRoom 410:00 AM - 11:00 AM
11 AM
12 PM
1 PM
2 PM
Prototype critique2:00 PM - 3:00 PM
3 PM
4 PM
5 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<div className={narrowWeekStoryContainer}>
<ScheduleStory
events={weekEvents}
view={createScheduleWeeklyView({
dayMinWidth: 128,
maxHour: 18,
minHour: 8,
})}
/>
</div>

August 2026

UTC
Customer summitDesign reviewPlanning offsite
7 AM
8 AM
9 AM
10 AM
Team syncRoom 410:00 AM - 11:00 AM
11 AM
12 PM
1 PM
2 PM
Prototype critique2:00 PM - 3:00 PM
3 PM
4 PM
5 PM
6 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
() => {
const availabilityPlugin = useScheduleAvailabilityPlugin({
getUnavailableRanges: getStoryUnavailableRanges,
});
return (
<ScheduleStory
events={weekEvents}
plugins={[availabilityPlugin]}
view={createScheduleWeeklyView({maxHour: 19, minHour: 7})}
/>
);
}

Use the left and right arrow keys to move between weeks.

August 2026

UTC
Customer summitDesign reviewPlanning offsite
8 AM
9 AM
10 AM
Team syncRoom 410:00 AM - 11:00 AM
11 AM
12 PM
1 PM
2 PM
Prototype critique2:00 PM - 3:00 PM
3 PM
4 PM
5 PM
() => {
const [viewDate, setViewDate] = useState<Instant>(() => defaultViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
hasHotkeys: true,
onViewDateChange: setViewDate,
});
return (
<div className={paginationHotkeysStoryContainer}>
<Text as="p" color="secondary" type="supporting">
Use the left and right arrow keys to move between weeks.
</Text>
<Schedule
categories={categories}
events={weekEvents}
highlightDate={defaultHighlightDate}
plugins={[paginationPlugin]}
timezoneID={localTimezoneID}
view={createScheduleWeeklyView({maxHour: 18, minHour: 8})}
viewDate={viewDate}
/>
</div>
);
}

August 2026

UTC
Planning offsiteRelease freeze
QA window
Launch window
Launch window
Launch window
8 AM
9 AM
Partner handoff9:30 AM - 10:45 AM
10 AM
11 AM
12 PM
Roadmap triage12:00 PM - 1:00 PM
1 PM
2 PM
Customer escalation review2:00 PM - 3:00 PM
Prototype critique2:30 PM - 3:30 PM
3 PM
Launch checklist3:30 PM - 4:00 PM
Account planning3:00 PM - 4:30 PM
4 PM
Team sync4:00 PM - 4:30 PM
Study readout4:45 PM - 5:30 PM
5 PM
Design review5:00 PM - 6:00 PM
function ResizableEventsStory(): React.JSX.Element {
const [viewDate, setViewDate] = useState<Instant>(() => defaultViewDate);
const [storyEvents, setStoryEvents] = useState(() => events);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
const resizePlugin = useScheduleEventResizePlugin({
onResize: ({end, event, start}) => {
setStoryEvents(currentEvents =>
currentEvents.map(currentEvent => {
if (
currentEvent.id !== event.id ||
typeof currentEvent.start !== 'number'
) {
return currentEvent;
}
return {...currentEvent, end, start};
}),
);
},
snapMinutes: 5,
});
return (
<Schedule
categories={categories}
events={storyEvents}
highlightDate={defaultHighlightDate}
plugins={[paginationPlugin, resizePlugin]}
timezoneID={localTimezoneID}
view={createScheduleWeeklyView({maxHour: 18, minHour: 8})}
viewDate={viewDate}
/>
);
}
<ResizableEventsStory />

August 2026

UTC
Planning offsiteRelease freeze
QA window
Launch window
Launch window
Launch window
8 AM
9 AM
Partner handoff9:30 AM - 10:45 AM
10 AM
11 AM
12 PM
Roadmap triage12:00 PM - 1:00 PM
1 PM
2 PM
Customer escalation review2:00 PM - 3:00 PM
Prototype critique2:30 PM - 3:30 PM
3 PM
Launch checklist3:30 PM - 4:00 PM
Account planning3:00 PM - 4:30 PM
4 PM
Team sync4:00 PM - 4:30 PM
Study readout4:45 PM - 5:30 PM
5 PM
Design review5:00 PM - 6:00 PM
function MovableEventsStory(): React.JSX.Element {
const views = useMemo(
(): {label: string; view: ScheduleView}[] => [
{label: 'Month', view: createScheduleMonthlyView()},
{
label: 'Week',
view: createScheduleWeeklyView({maxHour: 18, minHour: 8}),
},
],
[],
);
const [view, setView] = useState<ScheduleView>(views[1].view);
const [viewDate, setViewDate] = useState<Instant>(() => defaultViewDate);
const [storyEvents, setStoryEvents] = useState(() => events);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
const viewSelectorPlugin = useScheduleViewSelectorPlugin(views, {
onChangeView: setView,
});
const movePlugin = useScheduleEventMovePlugin({
onMove: ({end, event, start}) => {
setStoryEvents(currentEvents =>
currentEvents.map(currentEvent => {
if (currentEvent.id !== event.id) {
return currentEvent;
}
if (
typeof currentEvent.start === 'number' &&
typeof start === 'number' &&
typeof end === 'number'
) {
return {...currentEvent, end, start};
}
if (
typeof currentEvent.start !== 'number' &&
typeof start !== 'number' &&
typeof end !== 'number'
) {
return {...currentEvent, end, start};
}
return currentEvent;
}),
);
},
snapMinutes: 5,
});
return (
<Schedule
categories={categories}
events={storyEvents}
highlightDate={defaultHighlightDate}
plugins={[paginationPlugin, viewSelectorPlugin, movePlugin]}
timezoneID={localTimezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<MovableEventsStory />

August 2026

UTC
8 AM
9 AM
10 AM
11 AM
12 PM
1 PM
2 PM
3 PM
4 PM
5 PM
function CreatableEventsStory(): React.JSX.Element {
const [viewDate, setViewDate] = useState<Instant>(() => defaultViewDate);
const [storyEvents, setStoryEvents] = useState<CalendarEvent[]>(() => events);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
const popoverPlugin = useScheduleEventPopoverPlugin();
const createPlugin = useScheduleEventCreatePlugin({
defaultDurationMinutes: 60,
renderContent: ({close, draft}) => (
<CreateEventForm
draft={draft}
onCancel={close}
onCreate={title => {
setStoryEvents(currentEvents => [
...currentEvents,
{
category: 'Sync',
end: draft.end,
id: `created-${draft.start}`,
start: draft.start,
title,
},
]);
close();
}}
/>
),
snapMinutes: 15,
});
return (
<Schedule
categories={categories}
events={storyEvents}
highlightDate={defaultHighlightDate}
plugins={[paginationPlugin, createPlugin, popoverPlugin]}
timezoneID={localTimezoneID}
view={createScheduleWeeklyView({maxHour: 18, minHour: 8})}
viewDate={viewDate}
/>
);
}
function CreateEventForm({
draft,
onCancel,
onCreate,
}: {
draft: ScheduleEventDraft;
onCancel: () => void;
onCreate: (title: string) => void;
}): React.JSX.Element {
const [title, setTitle] = useState('');
const timeLabel = `${Temporal.Instant.fromEpochMilliseconds(draft.start)
.toZonedDateTimeISO(localTimezoneID)
.toLocaleString(undefined, {
hour: 'numeric',
minute: '2-digit',
weekday: 'short',
})}${Temporal.Instant.fromEpochMilliseconds(draft.end)
.toZonedDateTimeISO(localTimezoneID)
.toLocaleString(undefined, {hour: 'numeric', minute: '2-digit'})}`;
return (
<form
className={css({w: 80})}
onSubmit={submitEvent => {
submitEvent.preventDefault();
onCreate(title.trim() === '' ? 'Untitled event' : title.trim());
}}>
<Layout
content={
<LayoutContent className={css({display: 'grid', gap: 3})}>
<TextInput
hasAutoFocus
label="Title"
onChange={setTitle}
placeholder="Add a title"
value={title}
/>
<Text color="secondary" type="supporting">
{timeLabel}
</Text>
</LayoutContent>
}
footer={
<LayoutFooter
primaryButton={
<Button
label="Create"
size="sm"
type="submit"
variant="primary"
/>
}
secondaryButton={
<Button
label="Cancel"
onClick={onCancel}
size="sm"
variant="ghost"
/>
}
/>
}
header={<LayoutHeader title="New event" />}
height="auto"
/>
</form>
);
}
<CreatableEventsStory />

August 2026

UTC
Planning offsiteRelease freeze
QA window
Launch window
Launch window
Launch window
8 AM
9 AM
Partner handoff9:30 AM - 10:45 AM
10 AM
11 AM
Survey results review11:00 AM - 12:00 PM
12 PM
Roadmap triage12:00 PM - 1:00 PM
1 PM
2 PM
Customer escalation review2:00 PM - 3:00 PM
Prototype critique2:30 PM - 3:30 PM
3 PM
Launch checklist3:30 PM - 4:00 PM
Account planning3:00 PM - 4:30 PM
4 PM
Team sync4:00 PM - 4:30 PM
Study readout4:45 PM - 5:30 PM
5 PM
Design review5:00 PM - 6:00 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<ScheduleStory
view={createScheduleWeeklyView({
maxHour: 18,
minHour: 8,
weekStartsOn: 1,
})}
/>

August 2026

UTC
Customer summitDesign reviewPlanning offsite
8 AM
9 AM
10 AM
Team syncRoom 410:00 AM - 11:00 AM
11 AM
12 PM
1 PM
2 PM
Prototype critique2:00 PM - 3:00 PM
3 PM
4 PM
5 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<ScheduleStory
events={weekEvents}
view={createScheduleWeeklyView({
hiddenDays: [0, 6],
maxHour: 18,
minHour: 8,
})}
/>

August 2026

UTC
Planning offsiteRelease freeze
8 AM
9 AM
10 AM
11 AM
12 PM
1 PM
2 PM
Customer escalation review2:00 PM - 3:00 PM
Prototype critique2:30 PM - 3:30 PM
3 PM
Launch checklist3:30 PM - 4:00 PM
4 PM
Team sync4:00 PM - 4:30 PM
Study readout4:45 PM - 5:30 PM
5 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<ScheduleStory view={createScheduleDayView({maxHour: 18, minHour: 8})} />

August 2026

UTC
8 AM
Full-width intake8:00 AM - 9:00 AM
9 AM
Full-width documentation9:00 AM - 10:00 AM
10 AM
Simultaneous canceled visit10:00 AM - 11:00 AM
Simultaneous consultation10:00 AM - 11:00 AM
11 AM
12 PM
Partially overlapping session12:00 PM - 1:30 PM
Partial design review12:30 PM - 1:00 PM
1 PM
2 PM
Three-way operations2:00 PM - 3:30 PM
Three-way research2:15 PM - 3:15 PM
Three-way design2:30 PM - 3:00 PM
3 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<ScheduleStory
events={overlappingEvents}
view={createScheduleDayView({maxHour: 16, minHour: 8})}
/>

August 2026

UTC
8 AM
Full-width intake8:00 AM - 9:00 AM
9 AM
Full-width documentation9:00 AM - 10:00 AM
10 AM
Simultaneous canceled visit10:00 AM - 11:00 AM
Simultaneous consultation10:00 AM - 11:00 AM
11 AM
12 PM
Partially overlapping session12:00 PM - 1:30 PM
Partial design review12:30 PM - 1:00 PM
1 PM
2 PM
Three-way operations2:00 PM - 3:30 PM
Three-way research2:15 PM - 3:15 PM
Three-way design2:30 PM - 3:00 PM
3 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<ScheduleStory
events={overlappingEvents}
view={createScheduleDayView({
maxHour: 16,
minHour: 8,
overlapBehavior: 'indented',
})}
/>

August 2026

25Tue

1:38 AM - 2:38 AM
Past sync
2:48 AM - 3:48 AM
Customer escalation review
3:53 AM - 4:53 AM
Current design review
5:23 AM - 6:23 AM
Future planning session
7:08 AM - 8:08 AM
Release readiness
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
() => {
const now = Temporal.Now.instant();
const timezoneID = Intl.DateTimeFormat().resolvedOptions().timeZone;
const listEvents = [
createEventFromISO({
category: 'Sync',
end: now.subtract({minutes: 90}).toString(),
id: 'list-past-sync',
start: now.subtract({minutes: 150}).toString(),
title: 'Past sync',
}),
createEventFromISO({
category: 'Customer',
end: now.subtract({minutes: 20}).toString(),
id: 'list-past-escalation',
start: now.subtract({minutes: 80}).toString(),
title: 'Customer escalation review',
}),
createEventFromISO({
category: 'Design',
end: now.add({minutes: 45}).toString(),
id: 'list-current-review',
start: now.subtract({minutes: 15}).toString(),
title: 'Current design review',
}),
createEventFromISO({
category: 'Planning',
end: now.add({minutes: 135}).toString(),
id: 'list-future-planning',
start: now.add({minutes: 75}).toString(),
title: 'Future planning session',
}),
createEventFromISO({
category: 'Operations',
end: now.add({minutes: 240}).toString(),
id: 'list-future-release',
start: now.add({minutes: 180}).toString(),
title: 'Release readiness',
}),
];
return (
<ScheduleStory
events={listEvents}
highlightDate={now.epochMilliseconds}
timezoneID={timezoneID}
view={createScheduleListView({days: 7})}
viewDate={now.epochMilliseconds}
/>
);
}

August 2026

UTC
8 AM
9 AM
10 AM
11 AM
12 PM
1 PM
2 PM
3 PM
4 PM
5 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
() => {
const loader = useMemo<ScheduleEventSource>(
() => async () =>
new Promise(resolve => {
setTimeout(() => resolve(events), 900);
}),
[],
);
return (
<ScheduleStory
events={loader}
view={createScheduleWeeklyView({maxHour: 18, minHour: 8})}
/>
);
}

August 2026

UTC
8 AM
9 AM
10 AM
11 AM
12 PM
1 PM
2 PM
3 PM
4 PM
5 PM
function AsyncEventsWithToastStory(): React.JSX.Element {
const toast = useToast();
const loader = useMemo<ScheduleEventSource>(
() => async () => {
try {
await new Promise((_, reject) => {
setTimeout(() => reject(new Error('Unable to load events')), 900);
});
return [];
} catch {
toast({
body: 'Unable to load schedule events',
type: 'error',
uniqueID: 'schedule-events-load-error',
});
return [];
}
},
[toast],
);
return (
<ScheduleStory
events={loader}
view={createScheduleWeeklyView({maxHour: 18, minHour: 8})}
/>
);
}
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<ToastViewport>
<AsyncEventsWithToastStory />
</ToastViewport>

August 2026

UTC
Planning offsiteRelease freeze
QA window
Launch window
Launch window
Launch window
8 AM
9 AM
Partner handoff9:30 AM - 10:45 AM
10 AM
11 AM
12 PM
Roadmap triage12:00 PM - 1:00 PM
1 PM
2 PM
Customer escalation review2:00 PM - 3:00 PM
Prototype critique2:30 PM - 3:30 PM
3 PM
Launch checklist3:30 PM - 4:00 PM
Account planning3:00 PM - 4:30 PM
4 PM
Team sync4:00 PM - 4:30 PM
Study readout4:45 PM - 5:30 PM
5 PM
Design review5:00 PM - 6:00 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
() => {
const views = useMemo(
(): ScheduleViewSelectorOption[] => [
{hotkey: 'm', label: 'Month', view: createScheduleMonthlyView()},
{
hotkey: 'w',
label: 'Week',
view: createScheduleWeeklyView({maxHour: 18, minHour: 8}),
},
{
hotkey: 'd',
label: 'Day',
view: createScheduleDayView({maxHour: 18, minHour: 8}),
},
{hotkey: 'l', label: 'List', view: createScheduleListView({days: 7})},
],
[],
);
const [view, setView] = useState<ScheduleView>(views[1].view);
const viewSelectorPlugin = useScheduleViewSelectorPlugin(views, {
onChangeView: setView,
});
return <ScheduleStory plugins={[viewSelectorPlugin]} view={view} />;
}

August 2026

UTC
Planning offsiteRelease freeze
QA window
Launch window
Launch window
Launch window
8 AM
9 AM
Partner handoff9:30 AM - 10:45 AM
10 AM
11 AM
12 PM
Roadmap triage12:00 PM - 1:00 PM
1 PM
2 PM
Customer escalation review2:00 PM - 3:00 PM
Prototype critique2:30 PM - 3:30 PM
3 PM
Launch checklist3:30 PM - 4:00 PM
Account planning3:00 PM - 4:30 PM
4 PM
Team sync4:00 PM - 4:30 PM
Study readout4:45 PM - 5:30 PM
5 PM
Design review5:00 PM - 6:00 PM
() => {
const views = useMemo(
(): {label: string; view: ScheduleView}[] => [
{label: 'Month', view: createScheduleMonthlyView()},
{
label: 'Week',
view: createScheduleWeeklyView({maxHour: 18, minHour: 8}),
},
{label: 'Day', view: createScheduleDayView({maxHour: 18, minHour: 8})},
{label: 'List', view: createScheduleListView({days: 7})},
],
[],
);
const [view, setView] = useState<ScheduleView>(views[1].view);
const [viewDate, setViewDate] = useState<Instant>(() => defaultViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
const viewSelectorPlugin = useScheduleViewSelectorPlugin(views, {
onChangeView: setView,
});
return (
<div className={fillHeightStoryContainer}>
<Schedule
categories={categories}
events={events}
height="fill"
highlightDate={defaultHighlightDate}
plugins={[paginationPlugin, viewSelectorPlugin]}
timezoneID={localTimezoneID}
view={view}
viewDate={viewDate}
/>
</div>
);
}

August 2026

UTC
Planning offsiteRelease freeze
QA window
Launch window
Launch window
Launch window
8 AM
9 AM
Partner handoff9:30 AM - 10:45 AM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<div className={fillHeightStoryContainer}>
<ScheduleStory
height="fill"
view={createScheduleWeeklyView({maxHour: 10, minHour: 8})}
/>
</div>
Draft

August 2026

UTC
Planning offsiteRelease freeze
QA window
Launch window
Launch window
Launch window
8 AM
9 AM
Partner handoff9:30 AM - 10:45 AM
10 AM
11 AM
12 PM
Roadmap triage12:00 PM - 1:00 PM
1 PM
2 PM
Customer escalation review2:00 PM - 3:00 PM
Prototype critique2:30 PM - 3:30 PM
3 PM
Launch checklist3:30 PM - 4:00 PM
Account planning3:00 PM - 4:30 PM
4 PM
Team sync4:00 PM - 4:30 PM
Study readout4:45 PM - 5:30 PM
5 PM
Design review5:00 PM - 6:00 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
() => {
const customPlugin = useMemo<SchedulePlugin>(
() => ({
renderHeader(startContent, centerContent, endContent) {
return {
centerContent,
endContent: (
<>
{endContent}
<Button label="Export" />
</>
),
startContent: (
<>
{startContent}
<Badge color="info" label="Draft" size="sm" />
</>
),
};
},
}),
[],
);
return (
<ScheduleStory
plugins={[customPlugin]}
view={createScheduleWeeklyView({maxHour: 18, minHour: 8})}
/>
);
}

August 2026

Sun

Mon

Tue

Wed

Thu

Fri

Sat

26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
() => {
const views = useMemo(
(): ScheduleViewSelectorOption[] => [
{label: 'Month', view: createScheduleMonthlyView()},
{
label: 'Week',
view: createScheduleWeeklyView({maxHour: 18, minHour: 8}),
},
{label: 'List', view: createScheduleListView({days: 7})},
],
[],
);
const [view, setView] = useState<ScheduleView>(views[0].view);
const viewSelectorPlugin = useScheduleViewSelectorPlugin(views, {
onChangeView: setView,
});
const statusPlugin = useMemo<SchedulePlugin>(
() => ({
renderEventEndContent: ({event}) => {
if (event.id === 'customer-escalation') {
return (
<Tooltip content="Needs attention" hoverIndication="never">
<span aria-label="Needs attention" role="img">
<Icon color="warning" icon={TriangleAlert} size="sm" />
</span>
</Tooltip>
);
}
return event.id === 'offsite' ? (
<Tooltip content="Confirmed" hoverIndication="never">
<span aria-label="Confirmed" role="img">
<Icon color="success" icon={CircleCheck} size="sm" />
</span>
</Tooltip>
) : null;
},
}),
[],
);
const recurrencePlugin = useMemo<SchedulePlugin>(
() => ({
renderEventEndContent: ({event}) =>
event.category === 'Planning' ? (
<Tooltip content="Recurring" hoverIndication="never">
<span aria-label="Recurring" role="img">
<Icon icon={Repeat2} size="sm" />
</span>
</Tooltip>
) : null,
}),
[],
);
return (
<ScheduleStory
plugins={[viewSelectorPlugin, statusPlugin, recurrencePlugin]}
view={view}
/>
);
}

August 2026

Sun

Mon

Tue

Wed

Thu

Fri

Sat

26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
function EventPopoverStory(): React.JSX.Element {
const views = useMemo(
(): {label: string; view: ScheduleView}[] => [
{label: 'Month', view: createScheduleMonthlyView()},
{
label: 'Week',
view: createScheduleWeeklyView({maxHour: 18, minHour: 8}),
},
{label: 'Day', view: createScheduleDayView({maxHour: 18, minHour: 8})},
{label: 'List', view: createScheduleListView({days: 7})},
],
[],
);
const [view, setView] = useState<ScheduleView>(views[0].view);
const [viewDate, setViewDate] = useState<Instant>(() => defaultViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
const viewSelectorPlugin = useScheduleViewSelectorPlugin(views, {
onChangeView: setView,
});
const eventPopoverPlugin = useScheduleEventPopoverPlugin({
renderContent: ({event, close}) => (
<ScheduleEventPopoverContent
event={event}
onClose={close}
onDelete={e => window.alert(`Delete ${e.title}`)}
onEdit={e => window.alert(`Edit ${e.title}`)}
onRespond={(e, response) => window.alert(`${response} for ${e.title}`)}
/>
),
});
return (
<Schedule
categories={categories}
events={eventPopoverEvents}
highlightDate={defaultHighlightDate}
plugins={[paginationPlugin, viewSelectorPlugin, eventPopoverPlugin]}
timezoneID={localTimezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<EventPopoverStory />

August 2026

UTC
8 AM
9 AM
10 AM
11 AM
12 PM
1 PM
2 PM
3 PM
4 PM
5 PM
() => {
const [viewDate, setViewDate] = useState<Instant>(() => defaultViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
const eventPopoverPlugin = useScheduleEventPopoverPlugin({
hasCloseButton: true,
renderContent: ({event}) => (
<Layout
className={css({w: '64'})}
content={
<LayoutContent padding={4}>
<Badge color="info" label={event.category ?? 'Event'} size="sm" />
</LayoutContent>
}
header={<LayoutHeader title={event.title} />}
height="auto"
/>
),
});
return (
<Schedule
categories={categories}
events={eventPopoverEvents}
highlightDate={defaultHighlightDate}
plugins={[paginationPlugin, eventPopoverPlugin]}
timezoneID={localTimezoneID}
view={createScheduleWeeklyView({maxHour: 18, minHour: 8})}
viewDate={viewDate}
/>
);
}

August 2026

UTC
Maintenance window
8 AM
9 AM
10 AM
Open retro10:30 AM - 11:30 AM
11 AM
12 PM
1 PM
2 PM
Release checklist2:00 PM - 3:15 PM
3 PM
4 PM
Open sync4:00 PM - 4:30 PM
Notes review4:45 PM - 5:30 PM
5 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<ScheduleStory
categories={[]}
events={eventsWithoutCategories}
view={createScheduleWeeklyView({maxHour: 18, minHour: 8})}
/>

August 2026

UTC
8 AM
9 AM
Blue category9:00 AM - 9:30 AM
10 AM
Cyan category10:00 AM - 10:30 AM
11 AM
Gray category11:00 AM - 11:30 AM
12 PM
Green category12:00 PM - 12:30 PM
1 PM
Orange category1:00 PM - 1:30 PM
2 PM
Pink category2:00 PM - 2:30 PM
3 PM
Purple category3:00 PM - 3:30 PM
Unknown category keeps label3:00 PM - 3:30 PM
4 PM
Red category4:00 PM - 4:30 PM
Missing category uses default4:00 PM - 4:30 PM
5 PM
Teal category5:00 PM - 5:30 PM
6 PM
Yellow category6:00 PM - 6:30 PM
7 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
() => {
const fallbackEvents = [
...colorFallbackCategories.map((category, index) =>
createEventFromISO({
category: category.label,
end: timedISO(0, index + 9, 30),
id: `color-${category.color}`,
start: timedISO(0, index + 9),
title: `${category.label} category`,
}),
),
createEventFromISO({
category: 'Unmapped',
end: timedISO(1, 15, 30),
id: 'unknown-category',
start: timedISO(1, 15),
title: 'Unknown category keeps label',
}),
createEventFromISO({
end: timedISO(1, 16, 30),
id: 'missing-category',
start: timedISO(1, 16),
title: 'Missing category uses default',
}),
];
return (
<ScheduleStory
categories={colorFallbackCategories}
events={fallbackEvents}
view={createScheduleWeeklyView({maxHour: 20, minHour: 8})}
/>
);
}

August 2026

25Tue

function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<ScheduleStory events={[]} view={createScheduleListView({days: 7})} />

August 2026

UTC
Launch window
Launch windowStaged rollout
Launch windowStaged rollout
Staged rollout
12 AM
Overnight handoff11:00 PM - 2:00 AM
Regional briefing10:00 PM - 1:30 AM
1 AM
2 AM
3 AM
4 AM
5 AM
6 AM
7 AM
8 AM
9 AM
Design sprint9:00 AM - 6:00 PM
10 AM
11 AM
12 PM
1 PM
2 PM
3 PM
4 PM
5 PM
6 PM
7 PM
8 PM
9 PM
10 PM
Regional briefing10:00 PM - 1:30 AM
11 PM
Overnight handoff11:00 PM - 2:00 AM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<ScheduleStory
events={multiDayEvents}
view={createScheduleWeeklyView({maxHour: 24, minHour: 0})}
/>

August 2026

UTC
8 AM
9 AM
10 AM
11 AM
12 PM
1 PM
2 PM
3 PM
4 PM
5 PM
Global sync5:00 PM - 7:00 PM
6 PM
7 PM

August 2026

PDT
8 AM
9 AM
10 AM
Global sync10:00 AM - 12:00 PM
11 AM
12 PM
1 PM
2 PM
3 PM
4 PM
5 PM
6 PM
7 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
() => {
// Anchored to a fixed UTC time-of-day (not the viewer's local zone) so the
// same instant is shown side by side in two zones deterministically.
const utcToday = Temporal.Now.plainDateISO('UTC');
const utcInstant = (hour: number): string =>
utcToday
.toZonedDateTime({
plainTime: Temporal.PlainTime.from({hour}),
timeZone: 'UTC',
})
.toInstant()
.toString();
const sameInstantEvents = [
createEventFromISO({
category: 'Sync',
end: utcInstant(19),
id: 'global-sync',
start: utcInstant(17),
title: 'Global sync',
}),
];
return (
<div style={{display: 'grid', gap: 24}}>
<ScheduleStory
events={sameInstantEvents}
timezoneID="UTC"
view={createScheduleDayView({maxHour: 20, minHour: 8})}
viewDate={utcToday.toZonedDateTime('UTC').epochMilliseconds}
/>
<ScheduleStory
events={sameInstantEvents}
timezoneID="America/Los_Angeles"
view={createScheduleDayView({maxHour: 20, minHour: 8})}
viewDate={
utcToday.toZonedDateTime('America/Los_Angeles').epochMilliseconds
}
/>
</div>
);
}

August 2026

UTC
Planning offsiteRelease freeze
12 AM
1 AM
2 AM
3 AM
4 AM
5 AM
6 AM
7 AM
8 AM
9 AM
10 AM
11 AM
12 PM
1 PM
2 PM
Customer escalation review2:00 PM - 3:00 PM
Prototype critique2:30 PM - 3:30 PM
3 PM
Launch checklist3:30 PM - 4:00 PM
4 PM
Team sync4:00 PM - 4:30 PM
Study readout4:45 PM - 5:30 PM
5 PM
6 PM
7 PM
8 PM
9 PM
10 PM
11 PM

August 2026

UTC
Planning offsiteRelease freeze
8 PM
9 PM
10 PM
11 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<div style={{display: 'grid', gap: 24}}>
<ScheduleStory view={createScheduleDayView({maxHour: 24, minHour: 0})} />
<ScheduleStory view={createScheduleDayView({maxHour: 24, minHour: 20})} />
</div>

August 2026

UTC
Planning offsiteRelease freeze
8 AM
9 AM
10 AM
11 AM
12 PM
1 PM
2 PM
Customer escalation review2:00 PM - 3:00 PM
Prototype critique2:30 PM - 3:30 PM
3 PM
Launch checklist3:30 PM - 4:00 PM
4 PM
Team sync4:00 PM - 4:30 PM
Study readout4:45 PM - 5:30 PM
5 PM

August 2026

UTC
Planning offsiteRelease freeze
QA window
Launch window
Launch window
Launch window
8 AM
9 AM
Partner handoff9:30 AM - 10:45 AM
10 AM
11 AM
12 PM
Roadmap triage12:00 PM - 1:00 PM
1 PM
2 PM
Customer escalation review2:00 PM - 3:00 PM
Prototype critique2:30 PM - 3:30 PM
3 PM
Launch checklist3:30 PM - 4:00 PM
Account planning3:00 PM - 4:30 PM
4 PM
Team sync4:00 PM - 4:30 PM
Study readout4:45 PM - 5:30 PM
5 PM
Design review5:00 PM - 6:00 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<div style={{display: 'grid', gap: 24}}>
<ScheduleStory
view={createScheduleDayView({
hourHeight: 48,
maxHour: 18,
minHour: 8,
})}
/>
<ScheduleStory
view={createScheduleWeeklyView({
hourHeight: 132,
maxHour: 18,
minHour: 8,
})}
/>
</div>

August 2026

UTC
12 AM
1 AM
2 AM
Past sync2:38 AM - 3:38 AM
3 AM
4 AM
Design review4:38 AM - 5:38 AM
5 AM
6 AM
7 AM
8 AM
9 AM
10 AM
11 AM
12 PM
1 PM
2 PM
3 PM
4 PM
5 PM
6 PM
7 PM
8 PM
9 PM
10 PM
11 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
() => {
const now = Temporal.Now.instant();
const currentEvents = [
createEventFromISO({
category: 'Sync',
end: now.subtract({minutes: 30}).toString(),
id: 'past-sync',
start: now.subtract({minutes: 90}).toString(),
title: 'Past sync',
}),
createEventFromISO({
category: 'Design',
end: now.add({minutes: 90}).toString(),
id: 'active-review',
start: now.add({minutes: 30}).toString(),
title: 'Design review',
}),
];
return (
<ScheduleStory
events={currentEvents}
highlightDate={now.epochMilliseconds}
view={createScheduleDayView({maxHour: 24, minHour: 0})}
viewDate={now.epochMilliseconds}
/>
);
}

August 2026

UTC
12 AM
1 AM
2 AM
Earlier sync2:53 AM - 3:53 AM
3 AM
4 AM
Upcoming review4:38 AM - 5:38 AM
5 AM
6 AM
7 AM
8 AM
9 AM
10 AM
11 AM
12 PM
1 PM
2 PM
3 PM
4 PM
5 PM
6 PM
7 PM
8 PM
9 PM
10 PM
11 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
() => {
const now = Temporal.Now.instant();
const timezoneID = Intl.DateTimeFormat().resolvedOptions().timeZone;
const currentEvents = [
createEventFromISO({
category: 'Sync',
end: now.subtract({minutes: 15}).toString(),
id: 'current-24-past',
start: now.subtract({minutes: 75}).toString(),
title: 'Earlier sync',
}),
createEventFromISO({
category: 'Design',
end: now.add({minutes: 90}).toString(),
id: 'current-24-next',
start: now.add({minutes: 30}).toString(),
title: 'Upcoming review',
}),
];
return (
<ScheduleStory
events={currentEvents}
highlightDate={now.epochMilliseconds}
timezoneID={timezoneID}
view={createScheduleDayView({
hourHeight: 56,
maxHour: 24,
minHour: 0,
})}
viewDate={now.epochMilliseconds}
/>
);
}

August 2026

UTC
12 AM
1 AM
2 AM
Past event2:23 AM - 3:23 AM
3 AM
Current event3:38 AM - 4:38 AM
4 AM
5 AM
Future event5:08 AM - 6:08 AM
6 AM
7 AM
8 AM
9 AM
10 AM
11 AM
12 PM
1 PM
2 PM
3 PM
4 PM
5 PM
6 PM
7 PM
8 PM
9 PM
10 PM
11 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
() => {
const now = Temporal.Now.instant();
const stateEvents = [
createEventFromISO({
category: 'Sync',
end: now.subtract({minutes: 45}).toString(),
id: 'past-state',
start: now.subtract({minutes: 105}).toString(),
title: 'Past event',
}),
createEventFromISO({
category: 'Design',
end: now.add({minutes: 30}).toString(),
id: 'current-state',
start: now.subtract({minutes: 30}).toString(),
title: 'Current event',
}),
createEventFromISO({
category: 'Planning',
end: now.add({minutes: 120}).toString(),
id: 'future-state',
start: now.add({minutes: 60}).toString(),
title: 'Future event',
}),
];
return (
<ScheduleStory
events={stateEvents}
highlightDate={now.epochMilliseconds}
view={createScheduleDayView({maxHour: 24, minHour: 0})}
viewDate={now.epochMilliseconds}
/>
);
}

August 2026

UTC
Planning offsiteRelease freeze
QA window
Launch window
Launch window
Launch window
8 AM
9 AM
Partner handoff9:30 AM - 10:45 AM
10 AM
11 AM
12 PM
Roadmap triage12:00 PM - 1:00 PM
1 PM
2 PM
Customer escalation review2:00 PM - 3:00 PM
Prototype critique2:30 PM - 3:30 PM
3 PM
Launch checklist3:30 PM - 4:00 PM
Account planning3:00 PM - 4:30 PM
4 PM
Team sync4:00 PM - 4:30 PM
Study readout4:45 PM - 5:30 PM
5 PM
Design review5:00 PM - 6:00 PM
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<ScheduleStory
highlightDate={dayInstant(2)}
view={createScheduleWeeklyView({maxHour: 18, minHour: 8})}
viewDate={dayInstant(0)}
/>

Day 1

May 2026

UTC
8 AM

Day 2

May 2026

UTC
8 AM

Day 3

May 2026

UTC
8 AM

Day 4

May 2026

UTC
8 AM

Day 5

May 2026

UTC
8 AM

Day 6

May 2026

UTC
8 AM

Day 7

May 2026

UTC
8 AM

Day 8

May 2026

UTC
8 AM

Day 9

May 2026

UTC
8 AM

Day 10

May 2026

UTC
8 AM

Day 11

May 2026

UTC
8 AM

Day 12

May 2026

UTC
8 AM

Day 13

May 2026

UTC
8 AM

Day 14

May 2026

UTC
8 AM

Day 15

May 2026

UTC
8 AM

Day 16

May 2026

UTC
8 AM

Day 17

May 2026

UTC
8 AM

Day 18

May 2026

UTC
8 AM

Day 19

May 2026

UTC
8 AM

Day 20

May 2026

UTC
8 AM

Day 21

May 2026

UTC
8 AM

Day 22

May 2026

UTC
8 AM

Day 23

May 2026

UTC
8 AM

Day 24

May 2026

UTC
8 AM

Day 25

May 2026

UTC
8 AM

Day 26

May 2026

UTC
8 AM

Day 27

May 2026

UTC
8 AM

Day 28

May 2026

UTC
8 AM

Day 29

May 2026

UTC
8 AM

Day 30

May 2026

UTC
8 AM

Day 31

May 2026

UTC
8 AM
() => {
const highlightedDays = Array.from({length: 31}, (_, index) =>
Temporal.PlainDate.from({
day: index + 1,
month: 5,
year: 2026,
}).toZonedDateTime('UTC'),
);
const view = createScheduleDayView({maxHour: 9, minHour: 8});
return (
<div className={highlightedDayNumberGrid}>
{highlightedDays.map(day => {
const instant = day.epochMilliseconds;
return (
<div className={highlightedDayNumberExample} key={day.toString()}>
<Text as="p" weight="bold">
Day {day.day}
</Text>
<Schedule
events={[]}
highlightDate={instant}
plugins={[]}
timezoneID="UTC"
view={view}
viewDate={instant}
/>
</div>
);
})}
</div>
);
}

July 2025

Sun

Mon

Tue

Wed

Thu

Fri

Sat

29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
() => {
const viewDate =
Temporal.PlainDate.from('2025-07-15').toZonedDateTime(
'UTC',
).epochMilliseconds;
return (
<div className={automaticMonthRowsFillHeightContainer}>
<ScheduleStory
height="fill"
highlightDate={viewDate}
timezoneID="UTC"
view={createScheduleMonthlyView()}
viewDate={viewDate}
/>
</div>
);
}

August 2026

Sun

Mon

Tue

Wed

Thu

Fri

Sat

26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
function ScheduleStory({
categories: storyCategories = categories,
events: storyEvents = events,
height,
highlightDate = defaultHighlightDate,
plugins,
timezoneID = localTimezoneID,
view,
viewDate: initialViewDate = defaultViewDate,
}: {
categories?: ReadonlyArray<ScheduleCategory>;
events?: ScheduleEventSource;
height?: ScheduleHeight;
highlightDate?: Instant;
plugins?: SchedulePlugin[];
timezoneID?: string;
view: ScheduleView;
viewDate?: Instant;
}) {
const [viewDate, setViewDate] = useState<Instant>(() => initialViewDate);
const paginationPlugin = useSchedulePaginationPlugin({
onViewDateChange: setViewDate,
});
return (
<Schedule
categories={storyCategories}
events={storyEvents}
height={height}
highlightDate={highlightDate}
plugins={plugins ?? [paginationPlugin]}
timezoneID={timezoneID}
view={view}
viewDate={viewDate}
/>
);
}
<ScheduleStory
events={busyDayEvents}
view={createScheduleMonthlyView({monthRowHeight: 'auto'})}
/>

Read-only schedule shell for day, week, month, and list views.

PropTypeDefaultDescription
categoriesReadonlyArray<ScheduleCategory>Category definitions used to style events by their category value.
classNamestringAdditional CSS class names applied to the schedule root.
data-testidstringTest ID applied to the schedule root.
events*ScheduleEventSourceStatic events or an async event loader.
height"fill" | "auto"'auto'Height behavior. auto grows with the active view; fill occupies a finite-height parent and scrolls the view below the fixed toolbar.
highlightDateInstantInstant highlighted as the current date. Defaults to mount time.
pluginsReadonlyArray<SchedulePlugin>Header/rendering plugins.
refRef<HTMLDivElement>Ref forwarded to the schedule root.
styleCSSPropertiesInline styles applied to the schedule root.
timezoneIDstringIANA timezone ID used for date math and rendering.
view*ScheduleView<Options>View object returned by a createSchedule*View factory.
viewDate*InstantInstant used to choose the rendered range.

Default Google-Calendar-style content for the event popover. Renders the event color, title, date/time, and category in a MetadataList with icon-only labels, plus optional `description` and `location` rows, an attendee response footer, and optional edit/delete actions — each shown only when the corresponding data or callback is present. A close button is always rendered. Pass this to the event popover plugin's `renderContent` to wire actions, e.g. `renderContent: (event, controls) => <ScheduleEventPopoverContent event={event} onClose={controls.close} onEdit={...} />`.

PropTypeDefaultDescription
event*CalendarEvent<TAuxiliaryData>The event to display.
onClose*() => voidCloses the popover. Wired to the close button.
onDelete(event: CalendarEvent<TAuxiliaryData>) => voidCalled when the delete action is triggered. When omitted, no delete button is rendered.
onEdit(event: CalendarEvent<TAuxiliaryData>) => voidCalled when the edit action is triggered. When omitted, no edit button is rendered.
onRespond( event: CalendarEvent<TAuxiliaryData>, response: string | null, ) => voidCalled when the attendee response (Going / Not Going / Maybe) changes. The response is null when the selection is cleared.