Calendar
AppMonth / week / day / agenda / resource calendar with view switcher, full keyboard nav (PageUp/Down + T + arrow keys for day-step), per-event color and icon, all-day bars + timed pills, TR/EN locales, full interactions (anchored popover, drag-move, edge-resize, drag-create), in-house RRULE expansion (FREQ/INTERVAL/COUNT/UNTIL/BYDAY + exceptions), multi-calendar overlay with per-calendar visibility legend, ResourceView lanes with O(n²) conflict highlighting, agenda list (search + date grouping) and a composable MiniCalendar sidebar. WAI-ARIA grid pattern with live-region nav announcements ("Showing May 2026") and event-count cell labels ("Tuesday May 12, 3 events"). Optional Intl.DateTimeFormat-based time formatting for locale-aware clocks.
Mayıs 2026
Pzt
Sal
Çar
Per
Cum
Cmt
Paz
27
28
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
3
4
5
6
7
<Calendar
events={events}
view="month"
defaultDate={new Date(2026, 4, 13)}
onViewChange={setView}
locale="tr"
/>11 – 17 Mayıs 2026
Pzt
11
Sal
12
Çar
13
Per
14
Cum
15
Cmt
16
Paz
17
Tüm gün
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
<Calendar
events={events}
view="week"
defaultDate={new Date(2026, 4, 13)}
onViewChange={setView}
locale="tr"
workingHours={{ start: 9, end: 18, days: [1,2,3,4,5] }}
/>13 May 2026
Wednesday13
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
<Calendar
events={events}
view="day"
defaultDate={new Date(2026, 4, 13)}
onViewChange={setView}
locale="en"
workingHours={{ start: 9, end: 18, days: [1,2,3,4,5] }}
/>10 – 16 May 2026
Sun
10
Mon
11
Tue
12
Wed
13
Thu
14
Fri
15
Sat
16
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
// Lazy in-house RRULE expander — FREQ + INTERVAL + COUNT + UNTIL + BYDAY.
const events: Event[] = [
{
id: 'standup',
title: 'Daily standup',
start: new Date(2026, 4, 11, 9, 30),
end: new Date(2026, 4, 11, 9, 45),
rrule: 'FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;COUNT=20',
exceptions: [new Date(2026, 4, 13)], // skip team off-site
},
{
id: 'coffee',
title: 'Coffee with Ada',
start: new Date(2026, 4, 12, 8, 30),
end: new Date(2026, 4, 12, 9, 0),
rrule: 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU;COUNT=5',
},
];
<Calendar
events={events}
view="week"
defaultDate={new Date(2026, 4, 13)}
slotMinutes={15}
workingHours={{ start: 9, end: 18, days: [1, 2, 3, 4, 5] }}
/>10 – 16 May 2026
Sun
10
Mon
11
Tue
12
Wed
13
Thu
14
Fri
15
Sat
16
All-day
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
<Calendar
events={events}
view="week"
defaultDate={new Date(2026, 4, 13)}
slotMinutes={30}
workingHours={{ start: 9, end: 18, days: [1, 2, 3, 4, 5] }}
onEventCreate={({ start, end }) =>
setEvents((prev) => [...prev, { id: `n${Date.now()}`, title: 'New event', start, end }])
}
onEventUpdate={(updated) =>
setEvents((prev) => prev.map((e) => (e.id === updated.id ? updated : e)))
}
onEventDelete={(id) =>
setEvents((prev) => prev.filter((e) => e.id !== id))
}
/>May 2026
13
Studio A
Studio B
Boardroom
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
const resources = [
{ id: 'room-a', name: 'Studio A', color: 'primary' },
{ id: 'room-b', name: 'Studio B', color: 'success' },
{ id: 'room-c', name: 'Boardroom', color: 'warning' },
];
const events = [
{ id: 'r1', title: 'Sprint planning',
start: new Date(2026, 4, 13, 9, 0), end: new Date(2026, 4, 13, 11, 0),
resourceId: 'room-a' },
{ id: 'r2', title: 'Design crit', // overlaps r1 → ring-error
start: new Date(2026, 4, 13, 10, 30), end: new Date(2026, 4, 13, 12, 0),
resourceId: 'room-a' },
// …
];
<Calendar
events={events}
view="resource"
defaultDate={new Date(2026, 4, 13)}
resources={resources}
slotMinutes={15}
workingHours={{ start: 9, end: 18, days: [1, 2, 3, 4, 5] }}
/>10 – 16 May 2026
Sun
10
Mon
11
Tue
12
Wed
13
Thu
14
Fri
15
Sat
16
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
const calendars = [
{ id: 'work', name: 'Work', color: 'primary' },
{ id: 'personal', name: 'Personal', color: 'success' },
{ id: 'family', name: 'Family', color: 'warning' },
];
const events = [
{ id: 'm1', title: 'Design sync', start: ..., end: ..., calendarId: 'work' },
{ id: 'm2', title: 'Yoga', start: ..., end: ..., calendarId: 'personal' },
{ id: 'm3', title: 'Dinner — parents', start: ..., end: ..., calendarId: 'family' },
];
<Calendar
events={events}
view="week"
calendars={calendars}
onCalendarToggle={(id, visible) => console.log(id, visible)}
/>May 2026
<Calendar
events={events}
view="agenda"
defaultDate={new Date(2026, 4, 13)}
onViewChange={setView}
locale="en"
/>May 2026
S
M
T
W
T
F
S
10 – 16 May 2026
Sun
10
Mon
11
Tue
12
Wed
13
Thu
14
Fri
15
Sat
16
All-day
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
import { Calendar, MiniCalendar } from '@/modules/app/Calendar';
const [date, setDate] = useState(new Date(2026, 4, 13));
const [view, setView] = useState<View>('week');
<div className="grid grid-cols-[15rem_1fr] gap-3">
<MiniCalendar
value={date}
onChange={(d) => { setDate(d); setView('day'); }}
locale="en"
/>
<Calendar
events={events}
view={view}
defaultDate={date}
onViewChange={setView}
onDateChange={setDate}
/>
</div>