Building Blocks
The parts of the built-in sidebar are exported on their own, plus the chip that draws an event. Place them anywhere in your layout and bind them to one scheduler or several.
// The parts of the sidebar, and the chip
import { DateNavigator, SearchBox, CalendarList, DragSourceList, EventChip } from '@sv5ui/scheduler';
// The five views, for ViewDefinition.component
import { MonthView, WeekView, DayView, YearView, AgendaView } from '@sv5ui/scheduler';DateNavigator
A month calendar with a dot under every day that has events. Picking a day calls onSelect with its start; bind the same date to a scheduler and the two stay in step. A Today link sits under the grid.
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
|---|---|---|---|---|---|---|
| 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 | 8 |
Selected: Tuesday, October 20, 2026
October 20, 2026
October 20, 2026
Today GMT+7<script lang="ts">
import { now } from '@internationalized/date';
let date = $state(now(zone));
</script>
<!-- Picking a day sets date; the scheduler follows because date is bound to both.
events gives the dots: an EventInput array, series expanded for the month shown. -->
<DateNavigator {date} onSelect={(day) => (date = day)} {events} timeZone={zone} />
<Scheduler bind:events bind:date timeZone={zone} />DateNavigator props
| Prop | Type | Default |
|---|---|---|
date | ZonedDateTime | required |
onSelect | (date: ZonedDateTime) => void | - |
events | EventInput<T>[] | [] |
timeZone | TimeZoneId | device zone |
locale | string | 'en-US' |
weekStartsOn | WeekDay | 1 |
labels | Pick<SchedulerLabels, 'today'> | English |
ui | Partial<Record<DateNavigatorSlots, ClassNameValue>> | - |
class | ClassNameValue | - |
ref | HTMLElement | null | - |
DateNavigator slots
| Slot | Element |
|---|---|
root | The section |
calendar | The sv5ui Calendar |
today | The Today link under it |
SearchBox and CalendarList
Two inputs to the same filters the scheduler applies. The box binds value,
the list binds hiddenCalendars; pass both to the scheduler. Press / to focus the box from anywhere on this page.
My calendars
Monday, October 5
1 event · 15mTuesday, October 6
1 event · 15mWednesday, October 7
1 event · 15mThursday, October 8
1 event · 15mFriday, October 9
1 event · 15mMonday, October 12
1 event · 15mTuesday, October 13
1 event · 15mWednesday, October 14
1 event · 15mThursday, October 15
1 event · 15mFriday, October 16
2 events · 1h 45mSaturday, October 17
1 event · 45mMonday, October 19
2 events · 1h 45mTuesday, October 20
Today 3 events · 3h 15mWednesday, October 21
4 events · 3h 15mThursday, October 22
3 events · 1h 45mFriday, October 23
4 events · 4h 45mSaturday, October 24
1 event · 1hMonday, October 26
2 events · 1h 15mTuesday, October 27
1 event · 15mWednesday, October 28
2 events · 15mThursday, October 29
1 event · 15mFriday, October 30
1 event · 15m
<script lang="ts">
let search = $state('');
</script>
<!-- bind:value here, search there. The / key focuses the box from anywhere on the
page unless another input has focus; shortcut={null} turns that off. Other input
attributes (name, autocomplete, data-*) pass through to the input. -->
<SearchBox bind:value={search} shortcut="/" name="q" autocomplete="off" />
<Scheduler bind:events {search} />SearchBox props
Other input attributes (name, autocomplete, data-*) pass through to the input.
| Prop | Type | Default |
|---|---|---|
value | string | '' |
shortcut | string | null | '/' |
labels | Pick<SchedulerLabels, 'searchEvents'> | English |
ui | Partial<Record<SearchBoxSlots, ClassNameValue>> | - |
class | ClassNameValue | - |
ref | HTMLInputElement | null | - |
SearchBox slots
| Slot | Element |
|---|---|
root | The sv5ui Input |
shortcut | The Kbd hint at the end |
<script lang="ts">
let hiddenCalendars = $state<string[]>([]);
</script>
<!-- The list toggles ids in hiddenCalendars; the scheduler hides those calendars.
title={null} drops the heading when the list sits under one of your own. -->
<CalendarList {calendars} bind:hiddenCalendars title={null} />
<Scheduler bind:events {calendars} {hiddenCalendars} />CalendarList props
| Prop | Type | Default |
|---|---|---|
calendars | SchedulerCalendar[] | required |
hiddenCalendars | string[] | [] |
title | string | null | labels.calendars |
labels | Pick<SchedulerLabels, 'calendars'> | English |
item | Snippet<[CalendarListItemProps]> | a Checkbox row |
ui | Partial<Record<CalendarListSlots, ClassNameValue>> | - |
class | ClassNameValue | - |
ref | HTMLElement | null | - |
CalendarList slots
| Slot | Element |
|---|---|
root | The section |
title | The heading |
list | The ul |
item | Each li |
label | The label around checkbox and text |
swatch | The colour dot |
name | The calendar title |
Your Own Rows
The item snippet replaces each row of the list. The list still owns the state and hands you toggle.
My calendars
- Work
- Team
- Personal
- Travel
- Learning
- Birthdays
Hidden: personal
<script lang="ts">
import { Switch } from 'sv5ui';
import { CalendarList, type CalendarListItemProps } from '@sv5ui/scheduler';
// Tailwind ships only the classes it can see, so map colours to classes
const swatch: Record<string, string> = { primary: 'bg-primary', info: 'bg-info', success: 'bg-success' /* ... */ };
</script>
<!-- item replaces each row; the list keeps the state and gives you toggle -->
<CalendarList {calendars} bind:hiddenCalendars item={row} />
{#snippet row({ calendar, visible, toggle }: CalendarListItemProps)}
<div class="flex items-center justify-between py-1">
<span class="flex items-center gap-2 text-sm">
<span class={['size-2.5 rounded-full', swatch[calendar.color ?? 'primary']]}></span>
{calendar.title}
</span>
<Switch checked={visible} onCheckedChange={toggle} size="sm" />
</div>
{/snippet}CalendarListItemProps
| Prop | Type | Default |
|---|---|---|
calendar | SchedulerCalendar | - |
visible | boolean | - |
toggle | () => void | - |
DragSourceList
The backlog: a list of things not yet on the calendar, each row a dragSource. Drop one on any scheduler on the page and it becomes an event through onMutate; see Drag & Drop. The rows below use the item snippet.
Unscheduled
October 20, 2026
October 20, 2026
Today GMT+7<!-- The backlog. Each row is a dragSource; drop it on any scheduler on the page.
calendars colours the swatch from item.calendarId. -->
<DragSourceList items={backlog} {calendars} />
<Scheduler bind:events view="day" />
<!-- item replaces the content of each draggable row -->
{#snippet row({ item, color }: DragSourceListItemProps)}
<Badge label={item.title} {color} variant="soft" />
<span class="text-xs">{item.durationMinutes ?? 60} min</span>
{/snippet}DragSourceList props
| Prop | Type | Default |
|---|---|---|
items | DragSourceData<T>[] | required |
calendars | SchedulerCalendar[] | [] |
title | string | null | labels.unscheduled |
labels | Pick<SchedulerLabels, 'unscheduled' | 'duration'> | English |
item | Snippet<[DragSourceListItemProps<T>]> | title and duration |
ui | Partial<Record<DragSourceListSlots, ClassNameValue>> | - |
class | ClassNameValue | - |
ref | HTMLElement | null | - |
DragSourceListItemProps
| Prop | Type | Default |
|---|---|---|
item | DragSourceData<T> | - |
color | EventColor | - |
DragSourceList slots
| Slot | Element |
|---|---|
root | The section |
title | The heading |
list | The ul |
item | Each draggable row |
swatch | The colour dot |
name | The title |
duration | The duration text |
EventChip
The chip the grid draws, on its own. Eight colours, soft or solid, two sizes. Its shape
follows position: a time position is a block with the time under the title, a span position or none is a
pill. It does not look up calendars, so pass color yourself.
<!-- The chip on its own: eight colours, soft or solid, sm or md. position decides the
shape: a time position draws a block with the time, a span position a pill.
Without position it is a pill. It does not read calendars: pass color. -->
<EventChip {event} color="success" variant="solid" />
<EventChip {event} color="warning" size="sm" showTime={false} />
<!-- children replace the title and time -->
<EventChip {event} color="info">
<Icon name="lucide:video" size="12" /> {event.title}
</EventChip>EventChip props
Other button attributes pass through to the button.
| Prop | Type | Default |
|---|---|---|
event | SchedulerEvent<T> | required |
position | PositionedEvent<T> | - |
color | EventColor | event.color, else primary |
variant | 'soft' | 'solid' | 'soft' |
size | 'sm' | 'md' | 'md' |
showTime | boolean | true |
selected | boolean | false |
dragging | boolean | false |
locale | string | 'en-US' |
hour12 | boolean | locale default |
children | Snippet | - |
ui | Partial<Record<EventChipSlots, ClassNameValue>> | - |
class | ClassNameValue | - |
ref | HTMLElement | null | - |
EventChip slots
| Slot | Element |
|---|---|
root | The button, with data-sch-event-id |
swatch | The colour dot of a pill |
title | The title |
time | The time line |
A Layout of Your Own
One set of state, three parts, two calendars. The navigator, the search box and the list read and write the same variables as both grids, so a pick or a query changes everything at once. The code shows a two-column page layout; here the parts sit above the grids because the docs column is narrow.
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
|---|---|---|---|---|---|---|
| 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 | 8 |
My calendars
Monday, October 5
1 event · 15mTuesday, October 6
1 event · 15mWednesday, October 7
1 event · 15mThursday, October 8
1 event · 15mFriday, October 9
1 event · 15mMonday, October 12
1 event · 15mTuesday, October 13
1 event · 15mWednesday, October 14
1 event · 15mThursday, October 15
1 event · 15mFriday, October 16
2 events · 1h 45mSaturday, October 17
1 event · 45mMonday, October 19
2 events · 1h 45mTuesday, October 20
Today 3 events · 3h 15mWednesday, October 21
4 events · 3h 15mThursday, October 22
3 events · 1h 45mFriday, October 23
4 events · 4h 45mSaturday, October 24
1 event · 1hMonday, October 26
2 events · 1h 15mTuesday, October 27
1 event · 15mWednesday, October 28
2 events · 15mThursday, October 29
1 event · 15mFriday, October 30
1 event · 15m
<script lang="ts">
import { now } from '@internationalized/date';
import { CalendarList, DateNavigator, Scheduler, SearchBox } from '@sv5ui/scheduler';
let events = $state<EventInput[]>([/* ... */]);
let date = $state(now(zone));
let search = $state('');
let hiddenCalendars = $state<string[]>([]);
</script>
<!-- One set of state, three parts, two calendars. Every part reads and writes the
same variables, so the navigator, the search box and the list drive both grids. -->
<div class="grid gap-4 lg:grid-cols-[16rem_1fr]">
<aside class="space-y-4">
<DateNavigator {date} onSelect={(day) => (date = day)} {events} timeZone={zone} />
<SearchBox bind:value={search} />
<CalendarList {calendars} bind:hiddenCalendars />
</aside>
<div class="space-y-4">
<Scheduler bind:events bind:date {calendars} {hiddenCalendars} {search} timeZone={zone} toolbar={false} height={480} />
<Scheduler bind:events bind:date {calendars} {hiddenCalendars} {search} timeZone={zone} view="agenda" toolbar={false} height={320} />
</div>
</div>The Five Views
MonthView, WeekView, DayView, YearView and AgendaView are exported so a view definition of yours can reuse them with a different range. They expect
the full set of props the scheduler passes, so they are not for rendering on their own. See Custom Views & Layouts.
// The five view components are exported for one purpose: ViewDefinition.component.
// They need the full ViewProps the scheduler passes, so they are not rendered directly.
import { WeekView, type ViewDefinition } from '@sv5ui/scheduler';
const workWeek: ViewDefinition = {
name: 'workweek',
label: 'Work week',
layout: 'time-grid',
range: (anchor) => ({ start: monday(anchor), end: monday(anchor).add({ days: 5 }) }),
step: (anchor, direction) => anchor.add({ weeks: direction }),
component: WeekView
};Props
The Scheduler props the parts on this page bind to.
| Prop | Type | Default |
|---|---|---|
date | ZonedDateTime | today |
search | string | '' |
hiddenCalendars | string[] | [] |
calendars | SchedulerCalendar[] | [] |
events | EventInput<T>[] | - |
views | ViewDefinition<T>[] | [] |
Snippets
The item snippets of the two lists.
| Type | Fields |
|---|---|
CalendarListItemProps | calendar, visible, toggle |
DragSourceListItemProps | item, color |