Toolbar
The bar above the grid: Today, the arrows, the title and the view switcher. Add to it, hide it, or replace it with your own and keep every function it had.
The Built-in Toolbar
Parts
| Part | What it does |
|---|---|
Menu | Shows when there is a sidebar or an onMenu handler. Toggles the sidebar, then calls onMenu |
Today | Back to now, keeping the view. Label from labels.today |
Previous, Next | One period of the current view. Named labels.previous and labels.next |
Title | The view's title(), or shortTitle() when compact. A polite live region, so a screen reader hears the period change |
View switcher | sv5ui Tabs, a Select when compact. A group named labels.views. Lists built-in views and registered ones, in order |
Actions | Your toolbarActions snippet, in a group named labels.actions |
Extra Controls
toolbarActions renders at the end of the built-in toolbar. It takes no arguments: it is your markup, bound to
your state. The demo filters by calendar with a toggle group and adds a Create button.
Oct 19 – 25, 2026
<script lang="ts">
import { Button, ToggleGroup } from 'sv5ui';
let scope = $state('all');
</script>
<!-- toolbarActions renders at the end of the built-in toolbar, in a group named
labels.actions. It takes no arguments: it is your markup, bound to your state. -->
<Scheduler
bind:events
toolbarActions={actions}
filter={(event) => scope === 'all' || event.calendarId === scope}
>
{#snippet actions()}
<ToggleGroup
items={[{ value: 'all', label: 'All' }, { value: 'work', label: 'Work' }, { value: 'personal', label: 'Personal' }]}
bind:value={scope}
size="sm"
/>
<Button label="Create event" icon="lucide:plus" size="sm" onclick={createNow} />
{/snippet}
</Scheduler>Hiding It
toolbar={false} removes the bar. The grid still reacts to view and date, so
bind them and navigate from outside, as the demo two sections down does.
<!-- No toolbar at all. Navigate with bind:view and bind:date from outside. -->
<Scheduler bind:events bind:view bind:date toolbar={false} />Your Own Toolbar
Pass a snippet as toolbar and it renders where the built-in one was, inside the scheduler. Everything the built-in bar knows
arrives as arguments. The demo leaves the Year view out of the switcher and hides the switcher
when compact.
Oct 19 – 25, 2026
<script lang="ts">
import { Button, ToggleGroup } from 'sv5ui';
import { Scheduler, type ToolbarSnippetProps } from '@sv5ui/scheduler';
</script>
<!-- Your toolbar, rendered where the built-in one was. Everything you need arrives
as arguments; the Year view is left out of the switcher here. -->
<Scheduler bind:events toolbar={header} />
{#snippet header({ title, step, today, view, views, setView, compact }: ToolbarSnippetProps)}
<div class="flex flex-wrap items-center gap-3 border-b border-outline-variant/60 px-4 py-3">
<Button icon="lucide:chevron-left" aria-label="Previous" variant="ghost" color="surface" size="sm" onclick={() => step(-1)} />
<Button label="Today" variant="outline" color="surface" size="sm" onclick={today} />
<Button icon="lucide:chevron-right" aria-label="Next" variant="ghost" color="surface" size="sm" onclick={() => step(1)} />
<h2 class="text-lg font-semibold">{title}</h2>
{#if !compact}
<ToggleGroup
class="ms-auto"
items={views.filter(({ name }) => name !== 'year').map(({ name, label }) => ({ value: name, label }))}
value={view}
onValueChange={(value: string | undefined) => value && setView(value)}
size="sm"
/>
{/if}
</div>
{/snippet}interface ToolbarSnippetProps {
title: string; // 'Sep 14 – 20, 2026', from the view's title()
date: ZonedDateTime; // the anchor
range: DateRange; // what is on screen, after hiddenDays
view: string; // the current view name
views: { name: string; label: string }[]; // built-in and registered, in switcher order
scheduler: SchedulerContext; // timeZone, locale, labels, compact, now...
step: (direction: 1 | -1) => void; // one period back or forward
today: () => void;
navigate: (date: ZonedDateTime, view?: string) => void;
setView: (name: string) => void;
toggleSidebar: () => void;
sidebarOpen: boolean;
compact: boolean; // below compactBreakpoint
}Titles
title comes from the view definition's title(),
or shortTitle() when compact, and describes the days actually on screen: with hiddenDays hiding the weekend, a week reads "Sep 14 – 18". Use compact to change the layout of your own bar on a phone: drop the switcher into a menu, shorten the buttons.
Controls Outside the Scheduler
The snippet is for a bar inside the calendar. For controls in your page header, beside a
search box or a user menu, skip the snippet: hide the toolbar, bind view and date,
and change them from anywhere.
<script lang="ts">
import { now } from '@internationalized/date';
let view = $state('week');
let date = $state(now(zone));
</script>
<!-- The toolbar snippet renders inside the scheduler. For controls in your own page
header, above or beside the calendar, skip the snippet: bind view and date and
drive them from wherever you like. -->
<header class="flex items-center gap-2">
<Button label="Today" onclick={() => (date = now(zone))} />
<Button icon="lucide:chevron-left" onclick={() => (date = date.subtract({ weeks: 1 }))} />
<Button icon="lucide:chevron-right" onclick={() => (date = date.add({ weeks: 1 }))} />
<Select items={viewItems} bind:value={view} />
</header>
<Scheduler bind:events bind:view bind:date toolbar={false} />The Menu Button
With a sidebar, the menu button toggles it and then calls onMenu.
Without a sidebar the button appears only when onMenu is given, so an app can open its own navigation drawer from the calendar's bar. The demo counts
the presses: 0.
Oct 19 – 25, 2026
<!-- With a sidebar, the menu button toggles it and onMenu is called after the
toggle. Without a sidebar the button shows only when onMenu is given, so an
app can open its own navigation drawer from the calendar's toolbar. -->
<Scheduler bind:events onMenu={() => (drawerOpen = true)} />
<Drawer bind:open={drawerOpen}>...</Drawer>
<!-- In a custom toolbar, toggleSidebar and sidebarOpen do the same job -->
{#snippet header({ toggleSidebar, sidebarOpen }: ToolbarSnippetProps)}
<Button icon="lucide:menu" aria-label="Menu" aria-expanded={sidebarOpen} onclick={toggleSidebar} />
{/snippet}Props
The toolbar props, and the two bindings that replace it from outside.
| Prop | Type | Default |
|---|---|---|
toolbar | boolean | Snippet<[ToolbarSnippetProps]> | true |
toolbarActions | Snippet | - |
onMenu | () => void | - |
view | string | 'week' |
date | ZonedDateTime | today |
filter | (event: SchedulerEvent<T>) => boolean | - |
Snippets
What the toolbar snippet receives.
| Type | Fields |
|---|---|
ToolbarSnippetProps | title, date, range, view, views, scheduler, step, today, navigate, setView, toggleSidebar, sidebarOpen, compact |