Calendar
SvCalendar: a themeable month/year/decade calendar with single / range / week / multi selection, min-max, restricted + important dates and week numbers. The same component SvGrid mounts to edit a date cell - and usable standalone in any SvGrid app.
A live, editable Svelte 5 component example from the SvGrid gallery (Date & Time). Read the SvGrid UI component docs for the full API.
What this example shows
SvCalendar - a standalone, themeable calendar that is ALSO the SvGrid date cell editor. Everything here is the same component the grid mounts when you edit a date column; drop it into any app that already uses SvGrid.
Imports, features and API used
Imports: @svgrid/grid
Source code (250-calendar.svelte)
<script lang="ts">
/**
* SvCalendar - a standalone, themeable calendar that is ALSO the SvGrid date
* cell editor. Everything here is the same component the grid mounts when you
* edit a date column; drop it into any app that already uses SvGrid.
*/
import { SvCalendar } from '@svgrid/grid'
import type { SelectionMode, CalendarAnimation } from '@svgrid/grid'
let mode = $state<SelectionMode>('one')
let weekNumbers = $state(false)
let footer = $state(true)
let firstDayOfWeek = $state(0)
let months = $state(1)
let noWeekends = $state(false)
let animate = $state<CalendarAnimation>('slide')
let wheelNavigation = $state(true)
let value = $state<Date[]>([new Date()])
const fmt = new Intl.DateTimeFormat(undefined, { dateStyle: 'medium' })
const y = new Date().getFullYear()
const m = new Date().getMonth()
const importantDates = [new Date(y, m, 14), new Date(y, m, 25)]
// A tooltip for the important days (Smart-style importantDatesTemplate).
const labels: Record<number, string> = { 14: 'Team offsite', 25: 'Release day' }
const dateTooltip = (d: Date) =>
d.getMonth() === m ? labels[d.getDate()] : undefined
const restrictWeekends = (d: Date) => noWeekends && (d.getDay() === 0 || d.getDay() === 6)
const modes: SelectionMode[] = ['one', 'zeroOrOne', 'many', 'range', 'week', 'oneExtended']
const anims: CalendarAnimation[] = ['slide', 'fade', 'none']
</script>
<div class="wrap">
<header>
<h2>SvCalendar</h2>
<p>
A framework-free date engine behind a themed Svelte 5 view. It works standalone (below) and is
the <strong>date cell editor inside SvGrid</strong> - the exact same component. Every
<code>--sg-*</code> theme applies automatically.
</p>
</header>
<div class="controls">
<label>Selection
<select bind:value={mode}>
{#each modes as m (m)}<option value={m}>{m}</option>{/each}
</select>
</label>
<label>First day
<select bind:value={firstDayOfWeek}>
<option value={0}>Sunday</option>
<option value={1}>Monday</option>
</select>
</label>
<label>Panels
<select bind:value={months}>
<option value={1}>1</option><option value={2}>2</option><option value={3}>3</option>
</select>
</label>
<label>Animation
<select bind:value={animate}>
{#each anims as a (a)}<option value={a}>{a}</option>{/each}
</select>
</label>
<label class="chk"><input type="checkbox" bind:checked={wheelNavigation} /> Mouse-wheel nav</label>
<label class="chk"><input type="checkbox" bind:checked={weekNumbers} /> Week numbers</label>
<label class="chk"><input type="checkbox" bind:checked={footer} /> Footer</label>
<label class="chk"><input type="checkbox" bind:checked={noWeekends} /> Block weekends</label>
</div>
<div class="stage">
<SvCalendar
value={value}
selectionMode={mode}
{weekNumbers}
{footer}
{firstDayOfWeek}
{months}
{animate}
{wheelNavigation}
{dateTooltip}
importantDates={importantDates}
restrictedDates={restrictWeekends}
onChange={(dates) => (value = dates)}
/>
<aside class="readout">
<h3>Selected value</h3>
{#if value.length === 0}
<p class="empty">Nothing selected</p>
{:else if value.length <= 3}
<ul>{#each value as d (d.getTime())}<li>{fmt.format(d)}</li>{/each}</ul>
{:else}
<p><strong>{value.length}</strong> days</p>
<p class="range">{fmt.format(value[0]!)} – {fmt.format(value[value.length - 1]!)}</p>
{/if}
<p class="hint">Dots mark <em>important</em> dates (hover the 14th / 25th for a tooltip). Strikethrough marks restricted days. Scroll over the grid or use the arrows to change months - watch the transition.</p>
</aside>
</div>
</div>
<style>
.wrap { padding: 20px; max-width: 900px; display: flex; flex-direction: column; gap: 16px; }
header h2 { margin: 0 0 4px; font-size: 20px; font-weight: 700; }
header p { margin: 0; color: var(--sg-muted, #64748b); font-size: 13.5px; line-height: 1.5; max-width: 640px; }
code { background: var(--sg-row-hover-bg, #eef2ff); padding: 1px 5px; border-radius: 5px; font-size: 12px; }
.controls { display: flex; flex-wrap: wrap; gap: 14px; align-items: end; }
.controls label { display: flex; flex-direction: column; gap: 4px; font-size: 12px; font-weight: 600; color: var(--sg-muted, #64748b); }
.controls label.chk { flex-direction: row; align-items: center; gap: 6px; }
.controls select { padding: 5px 8px; border: 1px solid var(--sg-border, #cbd5e1); border-radius: 7px; background: var(--sg-input-bg, #fff); color: inherit; font: inherit; font-size: 13px; }
.stage { display: flex; gap: 24px; align-items: flex-start; flex-wrap: wrap; }
.readout { flex: 1; min-width: 200px; }
.readout h3 { margin: 0 0 8px; font-size: 13px; text-transform: uppercase; letter-spacing: 0.03em; color: var(--sg-muted, #64748b); }
.readout ul { margin: 0; padding-left: 18px; }
.readout li { font-size: 14px; margin-bottom: 2px; }
.readout .empty { color: var(--sg-muted, #94a3b8); font-style: italic; }
.readout .range { font-size: 13px; color: var(--sg-muted, #64748b); }
.readout .hint { margin-top: 14px; font-size: 12px; color: var(--sg-muted, #94a3b8); line-height: 1.5; }
</style>Related documentation
Related articles
- Real-Time Grids - Live WebSocket Updates in SvGrid - How to wire a high-frequency WebSocket feed into SvGrid without frame drops - covering stable row identity, RAF batching, and flash feedback done right.
- Building a Real-Time Trading Grid in Svelte - How to wire a WebSocket tick feed into SvGrid without dropping frames - rAF batching, stable row identity, flash animations, and the exact patterns that scale past 150 ticks per second.
- Building a Logistics / Fleet Tracking Grid in Svelte - How to build a live fleet operations grid with real-time telemetry updates, expandable trip history, and exception-first row styling.
More Date & Time examples
- Time picker - SvTimePicker: an analog clock-dial picker with 12/24-hour, minute snapping and hour to minute auto-switch. Drag the hand or click a number. The SvGrid time cell editor, usable standalone in any SvGrid app.
- Date-time picker - SvDateTimePicker: a formatted input plus a portalled dropdown with DATE / TIME tabs (calendar + clock). Type a masked value or pick it; invalid input reverts. min/max, nullable, 12/24-hour, spin buttons. The SvGrid datetime cell editor, standalone in any SvGrid app.
- Date-range input - SvDateRangeInput: a compact start/end field that opens a two-month range calendar with one-click presets (Today, Last 7 days, ...). Composes the same headless range engine as SvCalendar, and carries the shared editor contract - label, hint, error validation, dir (RTL) and localizable messages.
- Calendar - range + presets - SvCalendar as a date-range picker: selectionMode="range" with a one-click presets rail (Today, Last 7 days, This month, Year to date...), animated month navigation and mouse-wheel scrolling. Presets resolve relative to today. Same component, no extra dependency.
- Calendar - date of birth - SvCalendar as a date-of-birth picker: single selection with max clamped to today so future dates are blocked, opening on the decade (year) grid for fewer clicks to a birth year, with a live age readout. Same component SvGrid mounts to edit a date cell.