# Calendar

Composable single-date calendar with localized keyboard navigation and month/year controls.

- Package: `@mielui/svelte`
- Component version: `2.0.0`
- Depends on Mielui components: _internal/utils, button
- Shared utilities: utils.cn, hugeicons-icon

## Install

~~~~sh
pnpm dlx @mielui/svelte add calendar
~~~~

## API

This reference is generated at build time from the component manifest, public `index.ts`, and documentation examples below. Changes to those source files are reflected here in the published Markdown. Standard Svelte and HTML attributes accepted by the exported prop types are supported.


### Root

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[CalendarRootSnippetProps]> \| undefined | - | No | No | Content rendered inside. |
| id | string \| undefined | - | No | No | Id of the element. |
| placeholder | DateValue \| undefined | - | No | Yes | The placeholder date, used to control the view of the calendar when no value is present. |
| style | string \| StyleProperties \| null \| undefined | - | No | No | Inline styles for the element. |
| disabled | boolean \| undefined | - | No | No | Whether or not the calendar is disabled. |
| value | DateValue \| undefined | - | No | Yes | The value of the selected date in the calendar. |
| readonly | boolean \| undefined | - | No | No | Whether the calendar is readonly. When true, the user will be able to focus and navigate the calendar, but will not be able to select dates. |
| onValueChange | OnChangeFn<DateValue \| undefined> \| undefined | - | No | No | A callback function called when the value changes. |
| onPlaceholderChange | OnChangeFn<DateValue> \| undefined | - | No | No | A callback function called when the placeholder value changes. |
| preventDeselect | boolean \| undefined | - | No | No | Whether or not users can deselect a date once selected without selecting another date. |
| minValue | DateValue \| undefined | - | No | No | The minimum date that can be selected in the calendar. |
| maxValue | DateValue \| undefined | - | No | No | The maximum date that can be selected in the calendar. |
| pagedNavigation | boolean \| undefined | - | No | No | Applicable only when `numberOfMonths` is greater than 1. |
| weekStartsOn | WeekStartsOn \| undefined | - | No | No | The day of the week to start the calendar on, which must be a number between 0 and 6, where 0 is Sunday and 6 is Saturday. |
| weekdayFormat | "long" \| "narrow" \| "short" \| undefined | 'short' | No | No | How the string representation of the weekdays provided via the `weekdays` state store should be formatted. |
| isDateDisabled | DateMatcher \| undefined | - | No | No | A function that receives a date and returns `true` or `false` to indicate whether the date is disabled. |
| isDateUnavailable | DateMatcher \| undefined | - | No | No | Dates matching the provided matchers are marked as "unavailable." Unlike disabled dates, users can still focus and select unavailable dates. However, selecting an unavailable date renders the date picker as invalid. |
| fixedWeeks | boolean \| undefined | true | No | No | Display 6 weeks per month, regardless the month's number of weeks. This is useful for displaying a consistent calendar, where the size of the calendar doesn't change month to month. |
| numberOfMonths | number \| undefined | - | No | No | Determines the number of months to display on the calendar simultaneously. For navigation between months, refer to the `pagedNavigation` prop. |
| calendarLabel | string \| undefined | - | No | No | This label is exclusively used for accessibility, remaining hidden from the page. It's read by screen readers when the calendar is opened. The current month and year are automatically appended to the label, so you only need to provide the base label. |
| locale | string \| undefined | 'en-US' | No | No | The default locale setting. |
| initialFocus | boolean \| undefined | - | No | No | If `true`, the calendar will focus the selected day, today, or the first day of the month in that order depending on what is visible when the calendar is mounted. |
| disableDaysOutsideMonth | boolean \| undefined | true | No | No | Whether to disable the selection of days outside the current month. By default, days outside the current month are rendered to fill the calendar grid, but they are not selectable. Setting this prop to `true` will disable this behavior. |
| maxDays | number \| undefined | - | No | No | The maximum number of days that can be selected in multiple mode. When set, users cannot select more dates than this number. |
| monthFormat | "numeric" \| "long" \| "short" \| "narrow" \| "2-digit" \| ((month: number) => string) \| undefined | - | No | No | The format of the month names in the calendar. |
| yearFormat | "numeric" \| "2-digit" \| ((year: number) => string) \| undefined | - | No | No | The format of the year names in the calendar. |
| element | HTMLElement \| null \| undefined | null | No | Yes | Bindable reference to the DOM element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Cell

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[CalendarCellSnippetProps]> \| undefined | - | No | No | Content rendered inside. |
| id | string \| undefined | - | No | No | Id of the element. |
| style | string \| StyleProperties \| null \| undefined | - | No | No | Inline styles for the element. |
| date | CalendarDate \| CalendarDateTime \| ZonedDateTime | - | Yes | No | The date value of the cell. |
| month | CalendarDate \| CalendarDateTime \| ZonedDateTime | - | Yes | No | The month DateValue that this cell is being rendered in. |
| child | Snippet<[CalendarCellSnippetProps & { props: Record<string, unknown>; }]> \| undefined | - | No | No | Renders your own element in place of the default one. Spread the given `props` onto it. |
| element | HTMLElement \| null \| undefined | null | No | Yes | Bindable reference to the DOM element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Day

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[CalendarDaySnippetProps]> \| undefined | - | No | No | Content rendered inside. |
| id | string \| undefined | - | No | No | Id of the element. |
| style | string \| StyleProperties \| null \| undefined | - | No | No | Inline styles for the element. |
| child | Snippet<[CalendarDaySnippetProps & { props: Record<string, unknown>; }]> \| undefined | - | No | No | Renders your own element in place of the default one. Spread the given `props` onto it. |
| element | HTMLElement \| null \| undefined | null | No | Yes | Bindable reference to the DOM element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Grid

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| id | string \| undefined | - | No | No | Id of the element. |
| style | string \| StyleProperties \| null \| undefined | - | No | No | Inline styles for the element. |
| child | Snippet<[{ props: Record<string, unknown>; }]> \| undefined | - | No | No | Renders your own element in place of the default one. Spread the given `props` onto it. |
| element | HTMLElement \| null \| undefined | null | No | Yes | Bindable reference to the DOM element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### GridBody

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| id | string \| undefined | - | No | No | Id of the element. |
| style | string \| StyleProperties \| null \| undefined | - | No | No | Inline styles for the element. |
| child | Snippet<[{ props: Record<string, unknown>; }]> \| undefined | - | No | No | Renders your own element in place of the default one. Spread the given `props` onto it. |
| element | HTMLElement \| null \| undefined | null | No | Yes | Bindable reference to the DOM element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### GridHead

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| id | string \| undefined | - | No | No | Id of the element. |
| style | string \| StyleProperties \| null \| undefined | - | No | No | Inline styles for the element. |
| child | Snippet<[{ props: Record<string, unknown>; }]> \| undefined | - | No | No | Renders your own element in place of the default one. Spread the given `props` onto it. |
| element | HTMLElement \| null \| undefined | null | No | Yes | Bindable reference to the DOM element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### GridRow

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| id | string \| undefined | - | No | No | Id of the element. |
| style | string \| StyleProperties \| null \| undefined | - | No | No | Inline styles for the element. |
| child | Snippet<[{ props: Record<string, unknown>; }]> \| undefined | - | No | No | Renders your own element in place of the default one. Spread the given `props` onto it. |
| element | HTMLElement \| null \| undefined | null | No | Yes | Bindable reference to the DOM element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### HeadCell

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| id | string \| undefined | - | No | No | Id of the element. |
| style | string \| StyleProperties \| null \| undefined | - | No | No | Inline styles for the element. |
| child | Snippet<[{ props: Record<string, unknown>; }]> \| undefined | - | No | No | Renders your own element in place of the default one. Spread the given `props` onto it. |
| element | HTMLElement \| null \| undefined | null | No | Yes | Bindable reference to the DOM element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Header

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| id | string \| undefined | - | No | No | Id of the element. |
| style | string \| StyleProperties \| null \| undefined | - | No | No | Inline styles for the element. |
| child | Snippet<[{ props: Record<string, unknown>; }]> \| undefined | - | No | No | Renders your own element in place of the default one. Spread the given `props` onto it. |
| element | HTMLElement \| null \| undefined | null | No | Yes | Bindable reference to the DOM element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Heading

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[CalendarHeadingSnippetProps]> \| undefined | - | No | No | Content rendered inside. |
| id | string \| undefined | - | No | No | Id of the element. |
| style | string \| StyleProperties \| null \| undefined | - | No | No | Inline styles for the element. |
| child | Snippet<[CalendarHeadingSnippetProps & { props: Record<string, unknown>; }]> \| undefined | - | No | No | Renders your own element in place of the default one. Spread the given `props` onto it. |
| element | HTMLElement \| null \| undefined | null | No | Yes | Bindable reference to the DOM element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Month

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| class | string \| undefined | - | No | No | Classes added to the element. |
| month | { value: DateValue; weeks: DateValue[][]; dates: DateValue[]; } | - | Yes | No | Month data from the Root snippet. |
| weekdays | string[] | - | Yes | No | Weekday names from the Root snippet. |
| locale | string \| undefined | 'en-US' | No | No | BCP 47 locale used for names and number formats. |
| showHeading | boolean \| undefined | false | No | No | Shows the month name above the grid, for layouts with several months. |
| day | Snippet<[date: DateValue]> \| undefined | - | No | No | Custom content for each day cell. |



### MonthSelect

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[CalendarMonthSelectSnippetProps]> \| undefined | - | No | No | Content rendered inside. |
| id | string \| undefined | - | No | No | Id of the element. |
| style | string \| StyleProperties \| null \| undefined | - | No | No | Inline styles for the element. |
| child | Snippet<[CalendarMonthSelectSnippetProps & { props: Record<string, unknown>; }]> \| undefined | - | No | No | Renders your own element in place of the default one. Spread the given `props` onto it. |
| monthFormat | "numeric" \| "long" \| "short" \| "narrow" \| "2-digit" \| ((month: number) => string) \| undefined | - | No | No | How the month names should be formatted in the select options. |
| months | number[] \| undefined | - | No | No | An array of month numbers (1-12) to display in the select. This allows for flexible month selection, such as showing only specific months or seasons. |
| element | HTMLElement \| null \| undefined | null | No | Yes | Bindable reference to the DOM element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### NextButton

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| id | string \| undefined | - | No | No | Id of the element. |
| style | string \| StyleProperties \| null \| undefined | - | No | No | Inline styles for the element. |
| child | Snippet<[{ props: Record<string, unknown>; }]> \| undefined | - | No | No | Renders your own element in place of the default one. Spread the given `props` onto it. |
| element | HTMLElement \| null \| undefined | null | No | Yes | Bindable reference to the DOM element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### PrevButton

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| id | string \| undefined | - | No | No | Id of the element. |
| style | string \| StyleProperties \| null \| undefined | - | No | No | Inline styles for the element. |
| child | Snippet<[{ props: Record<string, unknown>; }]> \| undefined | - | No | No | Renders your own element in place of the default one. Spread the given `props` onto it. |
| element | HTMLElement \| null \| undefined | null | No | Yes | Bindable reference to the DOM element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### YearSelect

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[CalendarYearSelectSnippetProps]> \| undefined | - | No | No | Content rendered inside. |
| id | string \| undefined | - | No | No | Id of the element. |
| style | string \| StyleProperties \| null \| undefined | - | No | No | Inline styles for the element. |
| child | Snippet<[CalendarYearSelectSnippetProps & { props: Record<string, unknown>; }]> \| undefined | - | No | No | Renders your own element in place of the default one. Spread the given `props` onto it. |
| yearFormat | "numeric" \| "2-digit" \| ((year: number) => string) \| undefined | - | No | No | How the year should be formatted in the select options. |
| years | number[] \| undefined | - | No | No | An array of years to display in the select. This allows for complete control over which years appear, such as showing only years with data or excluding certain periods. |
| element | HTMLElement \| null \| undefined | null | No | Yes | Bindable reference to the DOM element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Public types

~~~~ts
import type { DateValue } from '@internationalized/date';
import type { DefaultProps, WithElement } from '@mielui/svelte/utils';
import type { Calendar as CalendarPrimitive, CalendarRootSnippetProps } from 'bits-ui';
import type { Snippet } from 'svelte';

export type CalendarProps = WithElement<
    Omit<Extract<CalendarPrimitive.RootProps, { type: 'single' }>, 'type' | 'child'>
>;
export type CalendarMonthProps = Omit<DefaultProps, 'children'> & {
    /** Month data from the Root snippet. */
    month: CalendarRootSnippetProps['months'][number];
    /** Weekday names from the Root snippet. */
    weekdays: string[];
    /** BCP 47 locale used for names and number formats. */
    locale?: string;
    /** Shows the month name above the grid, for layouts with several months. */
    showHeading?: boolean;
    /** Custom content for each day cell. */
    day?: Snippet<[date: DateValue]>;
};

export { default as Root } from './calendar.svelte';
export { default as Cell } from './calendar-cell.svelte';
export { default as Day } from './calendar-day.svelte';
export { default as Grid } from './calendar-grid.svelte';
export { default as GridBody } from './calendar-grid-body.svelte';
export { default as GridHead } from './calendar-grid-head.svelte';
export { default as GridRow } from './calendar-grid-row.svelte';
export { default as HeadCell } from './calendar-head-cell.svelte';
export { default as Header } from './calendar-header.svelte';
export { default as Heading } from './calendar-heading.svelte';
export { default as Month } from './calendar-month.svelte';
export { default as MonthSelect } from './calendar-month-select.svelte';
export { default as NextButton } from './calendar-next-button.svelte';
export { default as PrevButton } from './calendar-prev-button.svelte';
export { default as YearSelect } from './calendar-year-select.svelte';
~~~~

## Examples

### Constraints

~~~~svelte
<script lang="ts">
    import { CalendarDate, isWeekend } from '@internationalized/date';
    import * as Calendar from '@mielui/svelte/components/calendar';
</script>

<Calendar.Root
    calendarLabel="Appointment date"
    placeholder={new CalendarDate(2026, 9, 17)}
    minValue={new CalendarDate(2026, 9, 17)}
    maxValue={new CalendarDate(2026, 9, 30)}
    isDateDisabled={(date) => isWeekend(date, 'en-US')}
/>
~~~~

### Events

~~~~svelte
<script lang="ts">
    import { CalendarDate, type DateValue } from '@internationalized/date';
    import * as Calendar from '@mielui/svelte/components/calendar';

    let value = $state<DateValue | undefined>(new CalendarDate(2026, 9, 17));
    let month = $state('September 2026');
</script>

<div class="flex flex-col items-center gap-3">
    <Calendar.Root
        bind:value
        calendarLabel="Delivery date"
        preventDeselect
        onPlaceholderChange={(date) => {
            month = date.toDate('UTC').toLocaleDateString('en-US', {
                month: 'long',
                year: 'numeric',
                timeZone: 'UTC'
            });
        }}
    />
    <p class="text-sm text-foreground-muted">
        Showing {month}. Selected {value?.toString() ?? 'nothing'}, and a second click keeps it.
    </p>
</div>
~~~~

### Hero

~~~~svelte
<script lang="ts">
    import { CalendarDate, type DateValue } from '@internationalized/date';
    import * as Calendar from '@mielui/svelte/components/calendar';

    let value = $state<DateValue | undefined>(new CalendarDate(2026, 9, 17));
</script>

<div class="flex flex-col items-center gap-4">
    <div class="mielui-plate max-w-full">
        <Calendar.Root bind:value calendarLabel="Meeting date" />
    </div>
    <p class="text-sm text-foreground-muted">
        Meeting date<span class="ms-2 font-mono text-foreground">
            {value?.toString() ?? 'Not selected'}
        </span>
    </p>
</div>
~~~~

### Navigation

~~~~svelte
<script lang="ts">
    import { CalendarDate } from '@internationalized/date';
    import * as Calendar from '@mielui/svelte/components/calendar';

    const years = Array.from({ length: 101 }, (_, index) => 1930 + index);
</script>

<Calendar.Root placeholder={new CalendarDate(1995, 6, 15)} calendarLabel="Date of birth">
    {#snippet children({ months, weekdays })}
        <Calendar.Header>
            <Calendar.MonthSelect />
            <Calendar.YearSelect {years} />
        </Calendar.Header>
        {#each months as month (month.value.toString())}
            <Calendar.Month {month} {weekdays} />
        {/each}
    {/snippet}
</Calendar.Root>
~~~~

### Unavailable

~~~~svelte
<script lang="ts">
    import { CalendarDate, type DateValue } from '@internationalized/date';
    import * as Calendar from '@mielui/svelte/components/calendar';

    const booked = [8, 9, 15, 22];

    function isBooked(date: DateValue) {
        return date.month === 9 && booked.includes(date.day);
    }
</script>

<Calendar.Root
    calendarLabel="Room booking"
    placeholder={new CalendarDate(2026, 9, 1)}
    isDateUnavailable={isBooked}
    monthFormat="short"
    yearFormat="2-digit"
/>
~~~~

### Weeks

~~~~svelte
<script lang="ts">
    import { CalendarDate } from '@internationalized/date';
    import * as Calendar from '@mielui/svelte/components/calendar';
</script>

<Calendar.Root
    calendarLabel="Sprint start"
    placeholder={new CalendarDate(2026, 2, 10)}
    numberOfMonths={2}
    pagedNavigation
    weekStartsOn={1}
    weekdayFormat="narrow"
    fixedWeeks={false}
/>
~~~~

For the rendered reference, visit [/docs/components/calendar](/docs/components/calendar).
