Calendar

An accessible calendar for selecting and displaying dates.

February 2024
28
29
30
31
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
1
2

Features

  • Full keyboard navigation
  • Can be controlled or uncontrolled
  • Focus is fully managed
  • Localization support
  • Highly composable

Overview

The Calendar builder enables you to compose a fully accessible calendar for selecting and displaying dates.

Before jumping into the docs for this builder, it's recommended that you understand how we work with dates & times in Melt, which you can read about here .

Anatomy

  • Calendar: The container of the months and days of the calendar
  • Cell: A single date in the calendar
  • Grid: A month in the calendar
  • Previous Button: A button for navigating to the previous page of the calendar
  • Next Button: A button for navigating to the next page of the calendar
  • Heading: A visual heading for the calendar

Scaffold a Calendar

The following tutorial is designed to help you get started using the Calendar builder, and explain some of the concepts to help you understand how it works.

Let's start by initializing a calendar with the createCalendar builder function, and destructuring everything we'll need to compose it. We'll cover what each of these properties are in more detail as we go.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    elements: { calendar, heading, grid, cell, prevButton, nextButton },
    states: { months, headingValue, weekdays },
    helpers: { isDateDisabled, isDateUnavailable }
  } = createCalendar()
</script>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    elements: { calendar, heading, grid, cell, prevButton, nextButton },
    states: { months, headingValue, weekdays },
    helpers: { isDateDisabled, isDateUnavailable }
  } = createCalendar()
</script>
	

The calendar element is the root container for everything in the calendar, and all the other elements will be contained within it.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    elements: { calendar, heading, grid, cell, prevButton, nextButton },
    states: { months, headingValue, weekdays },
    helpers: { isDateDisabled, isDateUnavailable }
  } = createCalendar()
</script>
 
<div use:melt={$calendar}>
  <!-- ... -->
</div>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    elements: { calendar, heading, grid, cell, prevButton, nextButton },
    states: { months, headingValue, weekdays },
    helpers: { isDateDisabled, isDateUnavailable }
  } = createCalendar()
</script>
 
<div {...$calendar} use:calendar>
  <!-- ... -->
</div>
	

We can now add the header of our calendar, which will contain the heading and page navigation buttons (prevButton & nextButton).

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    elements: { calendar, heading, grid, cell, prevButton, nextButton },
    states: { months, headingValue, weekdays },
    helpers: { isDateDisabled, isDateUnavailable }
  } = createCalendar()
</script>
 
<div use:melt={$calendar}>
  <header>
    <button use:melt={$prevButton}> Previous Page </button>
    <div use:melt={$heading}>
      {$headingValue}
    </div>
    <button use:melt={$nextButton}> Next Page</button>
  </header>
</div>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    elements: { calendar, heading, grid, cell, prevButton, nextButton },
    states: { months, headingValue, weekdays },
    helpers: { isDateDisabled, isDateUnavailable }
  } = createCalendar()
</script>
 
<div {...$calendar} use:calendar>
  <header>
    <button {...$prevButton} use:prevButton> Previous Page </button>
    <div {...$heading} use:heading>
      {$headingValue}
    </div>
    <button {...$nextButton} use:nextButton> Next Page</button>
  </header>
</div>
	

Something you may notice is that we aren't using an HTML heading element for the heading. This is because the builder automatically adds an accessible heading to the calendar, which is not visible to sighted users, and will be the first thing the screen reader will announce when the user navigates to the calendar. The heading here is strictly for visual purposes.

The headingValue state is a string that contains the month and year of the current page of the calendar. It reacts to changes in the month and year states, and is formatted according to the locale prop.

Now that we've taken care of the header, we can add the meat of the calendar, which is the month(s) and their days.

We'll be using the months store to iterate over each month being displayed in the calendar, which defaults to 1 but can be changed with the numberOfMonths prop. The months store is an array of Month objects, which look like this:

    export type Month = {
  /**
   * A `DateValue` used to represent the month. Since days
   * from the previous and next months are included in the
   * calendar grid, we need a source of truth for the value
   * the grid is representing.
   */
  value: DateValue
 
  /**
   * An array of arrays representing the weeks in the calendar.
   * Each sub-array represents a week, and contains the dates for each
   * day in that week. This structure is useful for rendering the calendar
   * grid using a table, where each row represents a week and each cell
   * represents a day.
   */
  weeks: DateValue[][]
 
  /**
   * An array of all the dates in the current month, including dates from
   * the previous and next months that are used to fill out the calendar grid.
   * This array is useful for rendering the calendar grid in a customizable way,
   * as it provides all the dates that should be displayed in the grid in a flat
   * array.
   */
  dates: DateValue[]
}
	
    export type Month = {
  /**
   * A `DateValue` used to represent the month. Since days
   * from the previous and next months are included in the
   * calendar grid, we need a source of truth for the value
   * the grid is representing.
   */
  value: DateValue
 
  /**
   * An array of arrays representing the weeks in the calendar.
   * Each sub-array represents a week, and contains the dates for each
   * day in that week. This structure is useful for rendering the calendar
   * grid using a table, where each row represents a week and each cell
   * represents a day.
   */
  weeks: DateValue[][]
 
  /**
   * An array of all the dates in the current month, including dates from
   * the previous and next months that are used to fill out the calendar grid.
   * This array is useful for rendering the calendar grid in a customizable way,
   * as it provides all the dates that should be displayed in the grid in a flat
   * array.
   */
  dates: DateValue[]
}
	

Since we're taking the recommended approach of rendering the calendar grid using a table, we'll be using the weeks property of each month to render the rows of the table. We'll also use the weekdays state to render the column headers of the table, which is an array of formatted day names according to the locale prop.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    elements: { calendar, heading, grid, cell, prevButton, nextButton },
    states: { months, headingValue, weekdays },
    helpers: { isDateDisabled, isDateUnavailable }
  } = createCalendar()
</script>
 
<div use:melt={$calendar}>
  <header>
    <button use:melt={$prevButton}> Previous Page </button>
    <div use:melt={$heading}>
      {$headingValue}
    </div>
    <button use:melt={$nextButton}> Next Page</button>
  </header>
  {#each $months as month}
    <table use:melt={$grid}>
      <thead aria-hidden="true">
        <tr>
          {#each $weekdays as day}
            <th>{day}</th>
          {/each}
        </tr>
      </thead>
    </table>
  {/each}
</div>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    elements: { calendar, heading, grid, cell, prevButton, nextButton },
    states: { months, headingValue, weekdays },
    helpers: { isDateDisabled, isDateUnavailable }
  } = createCalendar()
</script>
 
<div {...$calendar} use:calendar>
  <header>
    <button {...$prevButton} use:prevButton> Previous Page </button>
    <div {...$heading} use:heading>
      {$headingValue}
    </div>
    <button {...$nextButton} use:nextButton> Next Page</button>
  </header>
  {#each $months as month}
    <table {...$grid} use:grid>
      <thead aria-hidden="true">
        <tr>
          {#each $weekdays as day}
            <th>{day}</th>
          {/each}
        </tr>
      </thead>
    </table>
  {/each}
</div>
	

We're setting the <thead /> to aria-hidden="true", because the day of the week is already read by screen readers as they focus each cell in the table, and it isn't useful to have it read twice.

Now we can finish off the calendar by rendering the weeks and days within each week.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    elements: { calendar, heading, grid, cell, prevButton, nextButton },
    states: { months, headingValue, weekdays },
    helpers: { isDateDisabled, isDateUnavailable }
  } = createCalendar()
</script>
 
<div use:melt={$calendar}>
  <header>
    <button use:melt={$prevButton}> Previous Page </button>
    <div use:melt={$heading}>
      {$headingValue}
    </div>
    <button use:melt={$nextButton}> Next Page</button>
  </header>
  {#each $months as month}
    <table use:melt={$grid}>
      <thead aria-hidden="true">
        <tr>
          {#each $weekdays as day}
            <th>{day}</th>
          {/each}
        </tr>
      </thead>
      <tbody>
        {#each month.weeks as weekDates}
          <tr>
            {#each weekDates as date}
              <td role="gridcell" aria-disabled={$isDateDisabled(date) || $isDateUnavailable(date)}>
                <div use:melt={$cell(date, month.value)}>
                  {date.day}
                </div>
              </td>
            {/each}
          </tr>
        {/each}
      </tbody>
    </table>
  {/each}
</div>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    elements: { calendar, heading, grid, cell, prevButton, nextButton },
    states: { months, headingValue, weekdays },
    helpers: { isDateDisabled, isDateUnavailable }
  } = createCalendar()
</script>
 
<div {...$calendar} use:calendar>
  <header>
    <button {...$prevButton} use:prevButton> Previous Page </button>
    <div {...$heading} use:heading>
      {$headingValue}
    </div>
    <button {...$nextButton} use:nextButton> Next Page</button>
  </header>
  {#each $months as month}
    <table {...$grid} use:grid>
      <thead aria-hidden="true">
        <tr>
          {#each $weekdays as day}
            <th>{day}</th>
          {/each}
        </tr>
      </thead>
      <tbody>
        {#each month.weeks as weekDates}
          <tr>
            {#each weekDates as date}
              <td role="gridcell" aria-disabled={$isDateDisabled(date) || $isDateUnavailable(date)}>
                <div {...$cell(date, month.value)} use:cell>
                  {date.day}
                </div>
              </td>
            {/each}
          </tr>
        {/each}
      </tbody>
    </table>
  {/each}
</div>
	

And that, along with your own styles and markup additions, is all you need to build a functional, fully accessible calendar component!

I know it may seem like it requires a lot of code to get a calendar up and running, but the functionality that the 43 lines of code above provide is quite powerful, which we'll learn more about in the following sections.

Placeholder

In this section, we'll learn about the placeholder props, which are used to change what the calendar displays when no date is selected.

Set the Starting Month

The Calendar has two placeholder props, placeholder (controlled), and defaultPlaceholder (uncontrolled), which are used to change what is displayed in the calendar when no date is selected.

By default, the placeholder will be set to the current date, but you can override this by passing a DateValue object to the defaultPlaceholder prop.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
  import { CalendarDate } from '@internationalized/date'
 
  const {
    /* ... */
  } = createCalendar({
    defaultPlaceholder: new CalendarDate(2021, 2, 1)
  })
</script>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
  import { CalendarDate } from '@internationalized/date'
 
  const {
    /* ... */
  } = createCalendar({
    defaultPlaceholder: new CalendarDate(2021, 2, 1)
  })
</script>
	
February 2021
31
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
1
2
3
4
5
6

Now our calendar starts out in February 2021, rather than the current month.

Values

The Calendar has two value props, value (controlled), and defaultValue (uncontrolled), which are used to determine what date is selected in the calendar.

Setting a Default Value

To have a date selected by default, we can use the value (controlled), or defaultValue (uncontrolled) props. If provided, the placeholder props will be set to this value.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
  import { CalendarDate } from '@internationalized/date'
 
  const {
    /* ... */
  } = createCalendar({
    defaultValue: new CalendarDate(2024, 1, 11)
  })
</script>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
  import { CalendarDate } from '@internationalized/date'
 
  const {
    /* ... */
  } = createCalendar({
    defaultValue: new CalendarDate(2024, 1, 11)
  })
</script>
	
January 2024
31
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

Reacting to Value Changes

To react to changes in the selected date, we have a few options available to us. We can pass in our own value store to the value prop, use the onValueChange change function , or use the value store returned as part of the createCalendar return object.

Which option you choose is up to you, but for the sake of this example, we'll be using the value store returned from createCalendar. This is a writable store that will be updated whenever the selected date changes. It's also the store that the value prop uses under the hood, so you can use it to control the selected date programmatically.

Let's say that when a user selects Halloween (October 31st), we want to display an alert that says "Happy Halloween!".

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
  import { CalendarDate, isSameDay } from '@internationalized/date'
 
  const halloween = new CalendarDate(2023, 10, 31)
 
  const {
    /* ... */
    states: { value /* ... */ }
  } = createCalendar({
    defaultPlaceholder: new CalendarDate(2023, 10, 1)
  })
 
  $: if ($value && isSameDay($value, halloween)) {
    alert('Happy Halloween! 🎃')
  }
</script>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
  import { CalendarDate, isSameDay } from '@internationalized/date'
 
  const halloween = new CalendarDate(2023, 10, 31)
 
  const {
    /* ... */
    states: { value /* ... */ }
  } = createCalendar({
    defaultPlaceholder: new CalendarDate(2023, 10, 1)
  })
 
  $: if ($value && isSameDay($value, halloween)) {
    alert('Happy Halloween! 🎃')
  }
</script>
	
October 2023
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

Using the Value

The value store returned from the createCalendar builder is a DateValue object with whatever type of date object that was passed via the placeholder or value props, which default to a CalendarDate object.

You can use this value to display the selected date in your own markup, or use its value within a form. Although for forms we highly recommend using our Date Picker , as it is a combination of the Calendar, Date Field , and Popover which makes it more similar to a native date picker, but with a lot more power.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
    states: { value /* ... */ }
  } = createCalendar()
</script>
 
<span>{$value.toString()}</span>
<!-- or -->
<input name="myDate" value={$value.toString()} />
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
    states: { value /* ... */ }
  } = createCalendar()
</script>
 
<span>{$value.toString()}</span>
<!-- or -->
<input name="myDate" value={$value.toString()} />
	

Appearance & Behavior

Fixed Weeks

If you press the previous button on the example below, you'll notice something that may be unappealing. The calendar navigates to the previous month, and since that month has an additional week, the calendar jumps in height.

January 2024
31
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

You could use CSS to add the extra space to accommodate for such a jump, or you can set the fixedWeeks prop to true, which will ensure the calendar always has the same number of weeks, regardless of the month.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
  import { CalendarDate } from '@internationalized/date'
 
  const {
    /* ... */
  } = createCalendar({
    defaultValue: new CalendarDate(2024, 1, 11),
    fixedWeeks: true
  })
</script>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
  import { CalendarDate } from '@internationalized/date'
 
  const {
    /* ... */
  } = createCalendar({
    defaultValue: new CalendarDate(2024, 1, 11),
    fixedWeeks: true
  })
</script>
	
February 2021
31
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
1
2
3
4
5
6
7
8
9
10
11
12
13

Multiple Months

By default, the calendar will display one month, but it supports displaying as many months as you'd like, using the numberOfMonths prop.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    numberOfMonths: 2
  })
</script>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    numberOfMonths: 2
  })
</script>
	
February - March 2024
28
29
30
31
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
1
2
25
26
27
28
29
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

Paged Navigation

By default, when the calendar has more than one month, the previous and next buttons will shift the calendar forward or backward by one month. However, you can change this behavior by setting the pagedNavigation prop to true, which will shift the calendar forward or backward by the number of months being displayed.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    numberOfMonths: 2,
    pagedNavigation: true
  })
</script>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    numberOfMonths: 2,
    pagedNavigation: true
  })
</script>
	
February - March 2024
28
29
30
31
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
1
2
3
4
5
6
7
8
9
25
26
27
28
29
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

Localization

The calendar will automatically format the content of the calendar according to the locale prop, which defaults to 'en-US', but can be changed to any locale supported by the Intl.DateTimeFormat constructor.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    locale: 'de'
  })
</script>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    locale: 'de'
  })
</script>
	
Februar 2024
29
30
31
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
1
2
3

Prevent Deselection

By default, users can deselect a selected date without selecting another, by selecting the date again. This results in the value potentially being undefined. If you'd like to disable this behavior, you can set the preventDeselect prop to true, which will prevent the user from being able to deselect dates.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    preventDeselect: true
  })
</script>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    preventDeselect: true
  })
</script>
	
February 2024
28
29
30
31
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
1
2

Multiple Selection

Sometimes, you may want to allow the user to select multiple dates in the calendar. To enable this behavior, you can set the multiple prop to true.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    multiple: true
  })
</script>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    multiple: true
  })
</script>
	
October 2023
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

Limiting Selected Dates

When allowing users to select multiple dates, you may want to limit the number of dates they can select. Since this could be handled in a variety of ways, the Calendar doesn't handle this for you, but does provide the means to do so.

We can use the onValueChange change function to limit the number of selected dates to 3.

In this first example, we're just preventing the user from being able to select another date if they've already selected 3. They'll need to deselect one of the dates before they can select another.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    multiple: true,
    onValueChange: ({ curr, next }) => {
      if (next && next.length > 3) {
        alert('You can only select 3 dates!')
        return curr
      } else {
        return next
      }
    }
  })
</script>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    multiple: true,
    onValueChange: ({ curr, next }) => {
      if (next && next.length > 3) {
        alert('You can only select 3 dates!')
        return curr
      } else {
        return next
      }
    }
  })
</script>
	
October 2023
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

An alternative, though not sure about the user experience implications, is to automatically deselect the oldest date when the user selects a new one after they've already selected 3.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    multiple: true,
    onValueChange: ({ next }) => {
      if (next && next.length > 3) {
        next.shift()
        return next
      } else {
        return next
      }
    }
  })
</script>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    multiple: true,
    onValueChange: ({ next }) => {
      if (next && next.length > 3) {
        next.shift()
        return next
      } else {
        return next
      }
    }
  })
</script>
	
October 2023
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

Using change functions is a powerful way to customize the way your calendar behaves!

Validation

Although possible to implement your own validation logic using change functions, the Calendar provides a few props that make it a bit easier.

Unavailable Dates

An unavailable date is a date that is not selectable, but is still visible and focusable in the calendar.

You can pass a Matcher function to the isDateUnavailable prop, which will be used to determine if a date is unavailable. The Matcher function is called with a DateValue object, and should return a boolean indicating whether the date is unavailable.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
  import { isWeekend } from '@internationalized/date'
 
  const {
    /* ... */
  } = createCalendar({
    isDateUnavailable: (date) => {
      return isWeekend(date, 'en')
    }
  })
</script>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
  import { isWeekend } from '@internationalized/date'
 
  const {
    /* ... */
  } = createCalendar({
    isDateUnavailable: (date) => {
      return isWeekend(date, 'en')
    }
  })
</script>
	

The unavailable dates will have the data-unavailable attribute set, which you can use to style differently than the other dates.

February 2024
28
29
30
31
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
1
2

Disabled Dates

Disabled dates are not selectable, nor are they focusable in the calendar. Keyboard navigation will skip over them entirely, and should be used for dates that have no meaning in the context of the calendar.

You can pass a Matcher function to the isDateDisabled prop, which will be used to determine if a date is disabled. The Matcher function is called with a DateValue object, and should return a boolean indicating whether the date is disabled.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    isDateDisabled: (date) => {
      return date.day <= 10
    }
  })
</script>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
 
  const {
    /* ... */
  } = createCalendar({
    isDateDisabled: (date) => {
      return date.day <= 10
    }
  })
</script>
	

In this example, we're disabling the first 10 days of each month.

February 2024
28
29
30
31
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
1
2

Minimum & Maximum Values

While the isDateDisabled prop is useful for more complex logic, the Calendar also provides the minValue and maxValue props, which are used to set the min and max selectable dates, which is nice if you're just trying to limit the range of dates that can be selected.

If a date is before the minValue, or after the maxValue, it will be disabled.

    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
  import { CalendarDate } from '@internationalized/date'
 
  const {
    /* ... */
  } = createCalendar({
    defaultPlaceholder: new CalendarDate(2023, 1, 25),
    minValue: new CalendarDate(2023, 1, 15),
    maxValue: new CalendarDate(2023, 2, 15)
  })
</script>
	
    <script lang="ts">
  import { createCalendar, melt } from '@melt-ui/svelte'
  import { CalendarDate } from '@internationalized/date'
 
  const {
    /* ... */
  } = createCalendar({
    defaultPlaceholder: new CalendarDate(2023, 1, 25),
    minValue: new CalendarDate(2023, 1, 15),
    maxValue: new CalendarDate(2023, 2, 15)
  })
</script>
	
January 2023
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

Composition

The calendar builder was designed to be as flexible as possible, and can be composed with other builders to create more complex components.

Month Selection

The calendar builder provides a prevButton and nextButton to enable navigation between pages of the calendar, but you may want to provide a way for the user to select a month from a list of months, or a year from a list of years.

This can be accomplished using the Select builder, and the setMonth and/or setYear helper functions provided by the Calendar builder. Here's an example demonstrating how to add a "month selector" to your calendar:

February 2024
28
29
30
31
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
1
2
3
4
5
6
7
8
9

API Reference

createCalendar

The builder function used to create the calendar component.

Props

Prop Default Type / Description
defaultValue -
DateValue | undefined

The default value for the calendar. When provided the placeholder will also assume this value.

value -
Writable<DateValue | undefined>

A writable store than can be used to control the value of the calendar from outside the builder. Useful if you want to sync the value of the calendar with another store used in your app.

onValueChange -
ChangeFn<DateValue | undefined>

A function called when the value of the calendar changes. It receives a single argument, which is an object containing curr and prev properties, whose values are the current and previous values of the value store. Whatever you return from this function will be set as the new value of the value store.

defaultPlaceholder CalendarDate
DateValue

The date that is used when the calendar is empty to determine what point in time the calendar should start at.

placeholder -
Writable<DateValue>

A writable store that can be used to control the placeholder date from outside the builder. When this prop is provided, the defaultPlaceholder prop is ignored, and the value of this store is used instead.

onPlaceholderChange -
ChangeFn<DateValue>

A function called when the placeholder value changes. It receives a single argument, which is an object containing curr and prev properties, whose values are the current and previous values of the placeholder store. Whatever you return from this function will be set as the new value of the placeholder store.

isDateUnavailable -
Matcher | undefined

A function that accepts a date and returns a boolean indicating whether the date is unavailable.

minValue -
DateValue | undefined

The minimum date that can be selected.

maxValue -
DateValue | undefined

The maximum date that can be selected.

disabled false
boolean

Whether the calendar is disabled.

readonly false
boolean

Whether the calendar is readonly.

locale 'en'
string

The locale to use when formatting the date.

preventDeselect false
boolean

Whether to prevent the user from deselecting the current value by pressing it.

pagedNavigation false
boolean

Whether to use paged navigation for the calendar.

weekStartsOn 0
0 | 1 | 2 | 3 | 4 | 5 | 6

The day of the week the calendar starts on. 0 is Sunday, 6 is Saturday, etc.

fixedWeeks false
boolean

Whether to always show 6 weeks in the calendar.

calendarLabel 'Event date'
string

An accessible label for the calendar.

ids -
CalendarIds

Override the default ids used by the various elements within the calendar.

Elements

Element Description

The container of the months and days of the calendar

A visual heading for the calendar

A grid representing a month of the calendar

A cell representing a single date in the calendar

A button which moves the calendar to the next page

A button which moves the calendar to the previous page

The element which contains the date segments

An individual segment of the date

The label for the calendar

The element containing the validation message

The hidden input used to submit the value within a form

States

State Description
value

A writable store which represents the current value of the calendar.

months

A readable store containing month objects for each month in the calendar.

weekdays

A readable store containing the days of the week, formatted to the locale prop.

headingValue

A readable store containing the heading for the calendar, formatted to the locale prop.

segmentValues

A writable store containing the current values of the date segments.

segmentContents

A readable store used to dynamically render the date segments.

segmentContentsObj

A readable store containing the current values of the date segments.

placeholder

A writable store which represents the placeholder value of the calendar.

isInvalid

A readable store which represents whether the calendar is invalid.

Helpers

Helper Description
nextPage

A function that moves the calendar to the next page.

prevPage

A function that moves the calendar to the previous page.

nextYear

A function that moves the calendar to the next year.

prevYear

A function that moves the calendar to the previous year.

setYear

A function that sets the year of the calendar.

setMonth

A function that sets the month of the calendar.

isDateDisabled

A function that returns whether the given date is disabled.

isDateUnavailable

A function that returns whether the given date is unavailable.

isDateSelected

A function that returns whether the given date is selected.

Options

Option Description
defaultValue

The default value for the calendar. When provided the placeholder will also assume this value.

onValueChange

A function called when the value of the calendar changes. It receives a single argument, which is an object containing curr and prev properties, whose values are the current and previous values of the value store. Whatever you return from this function will be set as the new value of the value store.

defaultPlaceholder

The date that is used when the calendar is empty to determine what point in time the calendar should start at.

onPlaceholderChange

A function called when the placeholder value changes. It receives a single argument, which is an object containing curr and prev properties, whose values are the current and previous values of the placeholder store. Whatever you return from this function will be set as the new value of the placeholder store.

isDateUnavailable

A function that accepts a date and returns a boolean indicating whether the date is unavailable.

minValue

The minimum date that can be selected.

maxValue

The maximum date that can be selected.

disabled

Whether the calendar is disabled.

readonly

Whether the calendar is readonly.

locale

The locale to use when formatting the date.

preventDeselect

Whether to prevent the user from deselecting the current value by pressing it.

pagedNavigation

Whether to use paged navigation for the calendar.

weekStartsOn

The day of the week the calendar starts on. 0 is Sunday, 6 is Saturday, etc.

fixedWeeks

Whether to always show 6 weeks in the calendar.

calendarLabel

An accessible label for the calendar.

ids

Override the default ids used by the various elements within the calendar.

calendar

The container of the months and days of the calendar

Data Attributes

Data Attribute Value
[data-invalid]

Present when the calendar is invalid.

[data-disabled]

Present when the calendar is disabled.

[data-readonly]

Present when the calendar is readonly.

[data-melt-calendar]

Present on all calendar elements.

Custom Events

Event Value
m-keydown (e: ) => void

grid

A grid representing a month of the calendar

Data Attributes

Data Attribute Value
[data-disabled]

Present when the calendar is disabled.

[data-melt-calendar-grid]

Present on all grid elements.

cell

A cell representing a single date in the calendar

Data Attributes

Data Attribute Value
[data-disabled]

Present when the date is disabled.

[data-selected]

Present when the date is selected.

[data-value]

The ISO string value of the date.

[data-unavailable]

Present when the date is unavailable.

[data-today]

Present when the date is today.

[data-outside-month]

Present when the date is outside the current month it is displayed in.

[data-outside-visible-months]

Present when the date is outside the months that are visible on the calendar.

[data-focused]

Present when the date is focused.

[data-melt-calendar-cell]

Present on all cell elements.

Custom Events

Event Value
m-click (e: ) => void

heading

A visual heading for the calendar

Data Attributes

Data Attribute Value
[data-invalid]

Present when the calendar is invalid.

[data-disabled]

Present when the calendar is disabled.

[data-melt-calendar-heading]

Present on all heading elements.

prevButton

A button which moves the calendar to the previous page

Data Attributes

Data Attribute Value
[data-disabled]

Present when the calendar is disabled.

[data-melt-calendar-prevButton]

Present on all prevButton elements.

Custom Events

Event Value
m-click (e: ) => void

nextButton

A button which moves the calendar to the next page

Data Attributes

Data Attribute Value
[data-disabled]

Present when the calendar is disabled.

[data-melt-calendar-nextButton]

Present on all nextButton elements.

Custom Events

Event Value
m-click (e: ) => void