Skip to main content

Overview

The Calendar component provides a visual calendar interface for selecting dates. It supports both single date selection and date range selection with customizable min/max dates.

Installation

import { Calendar } from '@svelte-atoms/core';

Basic Usage

<script>
  import { Calendar } from '@svelte-atoms/core';
</script>

<Calendar.Root>
  <Calendar.Header />
  <Calendar.Body>
    {#snippet children({ day })}
      <Calendar.Day {day} />
    {/snippet}
  </Calendar.Body>
</Calendar.Root>

Calendar.Root Props

value
Date
The selected date (single mode)
range
[Date | undefined, Date | undefined]
Selected date range [start, end]
start
Date
default:"today"
Start date of the range
end
Date
End date of the range
pivote
Date
default:"new Date()"
The currently displayed month/year
min
Date
Minimum selectable date
max
Date
Maximum selectable date
type
'single' | 'range'
default:"single"
Selection mode
extend
Record<string, unknown>
Additional custom properties
factory
Factory<CalendarBond>
Custom factory function for creating calendar bond
onchange
(ev: CustomEvent, params: { range: CalendarRange; pivote: Date }) => void
Callback fired when date selection changes
preset
string
default:"calendar"
Preset key for styling

Calendar.Day Props

day
Day
required
Day object containing date information
as
string
HTML element type to render
onclick
() => void
Click handler for the day
preset
string
default:"calendar.day"
Preset key for styling

Day Object Structure

The Day type contains the following properties:
type Day = {
  id: number;
  date: Date;
  dayOfMonth: number;
  offmonth: boolean;          // Day belongs to previous/next month
  today: boolean;             // Is today's date
  week: number;               // Week number (0-5)
  month: number;              // Month number
  disabled: boolean;          // Is disabled (outside min/max)
  weekend: boolean;           // Is weekend (Sunday)
  name: string;               // Short name (e.g., "Mon")
  fullname: string;           // Full name (e.g., "Monday")
  fromNextMonth: boolean;     // From next month
  fromPreviousMonth: boolean; // From previous month
};

Calendar.Header Props

Extends all HtmlAtomProps. Typically contains navigation controls for month/year.

Calendar.Body Props

Extends all HtmlAtomProps. Container for the calendar grid.

Calendar.WeekDay Props

Extends all HtmlAtomProps. Displays weekday names.

Subcomponents

Calendar.Root

Root container managing calendar state and date logic.

Calendar.Header

Header section typically containing month/year navigation.

Calendar.Body

Body section containing the calendar grid of days.

Calendar.Day

Individual day cell in the calendar.

Calendar.WeekDay

Weekday name labels (Mon, Tue, Wed, etc.).

Examples

Single Date Selection

<script>
  import { Calendar } from '@svelte-atoms/core';
  
  let selectedDate = $state<Date | undefined>(undefined);
</script>

<Calendar.Root bind:value={selectedDate} type="single">
  <Calendar.Header />
  <Calendar.Body>
    {#snippet children({ day })}
      <Calendar.Day {day} />
    {/snippet}
  </Calendar.Body>
</Calendar.Root>

{#if selectedDate}
  <p>Selected: {selectedDate.toDateString()}</p>
{/if}

Date Range Selection

<script>
  import { Calendar } from '@svelte-atoms/core';
  import type { CalendarRange } from '@svelte-atoms/core';
  
  let range = $state<CalendarRange>([undefined, undefined]);
</script>

<Calendar.Root bind:range type="range">
  <Calendar.Header />
  <Calendar.Body>
    {#snippet children({ day })}
      <Calendar.Day {day} />
    {/snippet}
  </Calendar.Body>
</Calendar.Root>

{#if range[0] && range[1]}
  <p>From: {range[0].toDateString()} To: {range[1].toDateString()}</p>
{/if}

With Min/Max Dates

<script>
  import { Calendar } from '@svelte-atoms/core';
  import { addDays, subDays } from 'date-fns';
  
  const today = new Date();
  const minDate = subDays(today, 7);
  const maxDate = addDays(today, 14);
</script>

<Calendar.Root min={minDate} max={maxDate}>
  <Calendar.Header />
  <Calendar.Body>
    {#snippet children({ day })}
      <Calendar.Day {day} />
    {/snippet}
  </Calendar.Body>
</Calendar.Root>

Custom Day Rendering

<script>
  import { Calendar } from '@svelte-atoms/core';
</script>

<Calendar.Root>
  <Calendar.Header />
  <Calendar.Body>
    {#snippet children({ day })}
      <button
        class="calendar-day"
        class:offmonth={day.offmonth}
        class:today={day.today}
        class:disabled={day.disabled}
        class:weekend={day.weekend}
      >
        {day.dayOfMonth}
      </button>
    {/snippet}
  </Calendar.Body>
</Calendar.Root>

With Custom Header

<script>
  import { Calendar } from '@svelte-atoms/core';
  import { format } from 'date-fns';
  
  let pivote = $state(new Date());
  
  function previousMonth() {
    pivote = new Date(pivote.getFullYear(), pivote.getMonth() - 1, 1);
  }
  
  function nextMonth() {
    pivote = new Date(pivote.getFullYear(), pivote.getMonth() + 1, 1);
  }
</script>

<Calendar.Root bind:pivote>
  <Calendar.Header class="flex items-center justify-between p-4">
    <button onclick={previousMonth}>&lt;</button>
    <span class="font-semibold">{format(pivote, 'MMMM yyyy')}</span>
    <button onclick={nextMonth}>&gt;</button>
  </Calendar.Header>
  
  <Calendar.Body>
    {#snippet children({ day })}
      <Calendar.Day {day} />
    {/snippet}
  </Calendar.Body>
</Calendar.Root>

Accessibility

  • Keyboard navigation with arrow keys
  • Enter/Space to select dates
  • Screen reader support with ARIA attributes
  • Disabled dates are not selectable
  • Visual indicators for today, selected dates, and date ranges

Build docs developers (and LLMs) love