Calendar

Displays dates and days of the week, facilitating date-related interactions.

Su
Mo
Tu
We
Th
Fr
Sa
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
7
8
9
10
11
	<script lang="ts">
  import { Calendar } from "bits-ui";
  import CaretLeft from "phosphor-svelte/lib/CaretLeft";
  import CaretRight from "phosphor-svelte/lib/CaretRight";
  import { getLocalTimeZone, today } from "@internationalized/date";
 
  const isDateUnavailable: Calendar.RootProps["isDateUnavailable"] = (date) => {
    return date.day === 17 || date.day === 18;
  };
 
  let value = $state(today(getLocalTimeZone()));
</script>
 
<Calendar.Root
  class="mt-6 rounded-[15px] border border-dark-10 bg-background-alt p-[22px] shadow-card"
  {isDateUnavailable}
  weekdayFormat="short"
  fixedWeeks={true}
  type="single"
  bind:value
>
  {#snippet children({ months, weekdays })}
    <Calendar.Header class="flex items-center justify-between">
      <Calendar.PrevButton
        class="inline-flex size-10 items-center justify-center rounded-9px bg-background-alt hover:bg-muted active:scale-98 active:transition-all"
      >
        <CaretLeft class="size-6" />
      </Calendar.PrevButton>
      <Calendar.Heading class="text-[15px] font-medium" />
      <Calendar.NextButton
        class="inline-flex size-10 items-center justify-center rounded-9px bg-background-alt hover:bg-muted active:scale-98 active:transition-all"
      >
        <CaretRight class="size-6" />
      </Calendar.NextButton>
    </Calendar.Header>
    <div
      class="flex flex-col space-y-4 pt-4 sm:flex-row sm:space-x-4 sm:space-y-0"
    >
      {#each months as month, i (i)}
        <Calendar.Grid class="w-full border-collapse select-none space-y-1">
          <Calendar.GridHead>
            <Calendar.GridRow class="mb-1 flex w-full justify-between">
              {#each weekdays as day}
                <Calendar.HeadCell
                  class="w-10 rounded-md text-xs !font-normal text-muted-foreground"
                >
                  <div>{day.slice(0, 2)}</div>
                </Calendar.HeadCell>
              {/each}
            </Calendar.GridRow>
          </Calendar.GridHead>
          <Calendar.GridBody>
            {#each month.weeks as weekDates}
              <Calendar.GridRow class="flex w-full">
                {#each weekDates as date}
                  <Calendar.Cell
                    {date}
                    month={month.value}
                    class="relative size-10 !p-0 text-center text-sm"
                  >
                    <Calendar.Day
                      class="group relative inline-flex size-10 items-center justify-center whitespace-nowrap rounded-9px border border-transparent bg-transparent p-0 text-sm font-normal text-foreground hover:border-foreground data-[disabled]:pointer-events-none data-[outside-month]:pointer-events-none data-[selected]:bg-foreground data-[selected]:font-medium data-[disabled]:text-foreground/30 data-[selected]:text-background data-[unavailable]:text-muted-foreground data-[unavailable]:line-through"
                    >
                      <div
                        class="absolute top-[5px] hidden size-1 rounded-full bg-foreground group-data-[today]:block group-data-[selected]:bg-background"
                      ></div>
                      {date.day}
                    </Calendar.Day>
                  </Calendar.Cell>
                {/each}
              </Calendar.GridRow>
            {/each}
          </Calendar.GridBody>
        </Calendar.Grid>
      {/each}
    </div>
  {/snippet}
</Calendar.Root>

Structure

	<script lang="ts">
	import { Calendar } from "bits-ui";
</script>
 
<Calendar.Root>
	{#snippet children({ months, weekdays })}
		<Calendar.Header>
			<Calendar.PrevButton />
			<Calendar.Heading />
			<Calendar.NextButton />
		</Calendar.Header>
 
		{#each months as month}
			<Calendar.Grid>
				<Calendar.GridHead>
					<Calendar.GridRow>
						{#each weekdays as day}
							<Calendar.HeadCell>
								{day}
							</Calendar.HeadCell>
						{/each}
					</Calendar.GridRow>
				</Calendar.GridHead>
				<Calendar.GridBody>
					{#each month.weeks as weekDates}
						<Calendar.GridRow>
							{#each weekDates as date}
								<Calendar.Cell {date} month={month.value}>
									<Calendar.Day />
								</Calendar.Cell>
							{/each}
						</Calendar.GridRow>
					{/each}
				</Calendar.GridBody>
			</Calendar.Grid>
		{/each}
	{/snippet}
</Calendar.Root>

Placeholder

The placeholder prop for the Calendar.Root component determines what date our calendar should start with when the user hasn't selected a date yet. It also determines the current "view" of the calendar.

As the user navigates through the calendar, the placeholder will be updated to reflect the currently focused date in that view.

By default, the placeholder will be set to the current date, and be of type CalendarDate.

Managing Placeholder State

Bits UI offers several approaches to manage and synchronize the component's placeholder state, catering to different levels of control and integration needs.

1. Two-Way Binding

For seamless state synchronization, use Svelte's bind:placeholder directive. This method automatically keeps your local state in sync with the component's internal state.

	<script lang="ts">
	import { Calendar } from "bits-ui";
	import { CalendarDateTime } from "@internationalized/date";
	let myPlaceholder = $state(new CalendarDateTime(2024, 8, 3, 12, 30));
</script>
 
<button onclick={() => (myPlaceholder = new CalendarDate(2024, 8, 3))}>
	Set placeholder to August 3rd, 2024
</button>
 
<Calendar.Root bind:placeholder={myPlaceholder}>
	<!-- ... -->
</Calendar.Root>

Key Benefits

  • Simplifies state management
  • Automatically updates myPlaceholder when the internal state changes
  • Allows external control (e.g., changing the placeholder via a separate button/programmatically)

2. Change Handler

For more granular control or to perform additional logic on state changes, use the onPlaceholderChange prop. This approach is useful when you need to execute custom logic alongside state updates.

	<script lang="ts">
	import { Calendar } from "bits-ui";
	import { CalendarDateTime } from "@internationalized/date";
	let myPlaceholder = $state(new CalendarDateTime(2024, 8, 3, 12, 30));
</script>
 
<Calendar.Root
	placeholder={myPlaceholder}
	onPlaceholderChange={(p) => {
		placeholder = p;
	}}
>
	<!-- ... -->
</Calendar.Root>

Use Cases

  • Implementing custom behaviors on placeholder change
  • Integrating with external state management solutions
  • Triggering side effects (e.g., logging, data fetching)

3. Fully Controlled

For complete control over the component's placeholder state, use the controlledPlaceholder prop. This approach requires you to manually manage the state, giving you full control over when and how the component responds to change events.

To implement controlled state:

  1. Set the controlledPlaceholder prop to true on the Calendar.Root component.
  2. Provide a placeholder prop to Calendar.Root, which should be a variable holding the current state.
  3. Implement an onPlaceholderChange handler to update the state when the internal state changes.
	<script lang="ts">
	import { Calendar } from "bits-ui";
	let myPlaceholder = $state();
</script>
 
<Calendar.Root
	controlledPlaceholder
	placeholder={myPlaceholder}
	onPlaceholderChange={(p) => (myPlaceholder = p)}
>
	<!-- ... -->
</Calendar.Root>

When to Use

  • Implementing complex logic
  • Coordinating multiple UI elements
  • Debugging state-related issues

Managing Value State

Bits UI offers several approaches to manage and synchronize the component's value state, catering to different levels of control and integration needs.

1. Two-Way Binding

For seamless state synchronization, use Svelte's bind:value directive. This method automatically keeps your local state in sync with the component's internal state.

	<script lang="ts">
	import { Calendar } from "bits-ui";
	import { CalendarDateTime } from "@internationalized/date";
	let myValue = $state(new CalendarDateTime(2024, 8, 3, 12, 30));
</script>
 
<button onclick={() => (myValue = myValue.add({ days: 1 }))}> Add 1 day </button>
<Calendar.Root bind:value={myValue}>
	<!-- ... -->
</Calendar.Root>

Key Benefits

  • Simplifies state management
  • Automatically updates myValue when the internal state changes
  • Allows external control (e.g., changing the value via a separate button/programmatically)

2. Change Handler

For more granular control or to perform additional logic on state changes, use the onValueChange prop. This approach is useful when you need to execute custom logic alongside state updates.

	<script lang="ts">
	import { Calendar } from "bits-ui";
	import { CalendarDateTime } from "@internationalized/date";
	let myValue = $state(new CalendarDateTime(2024, 8, 3, 12, 30));
</script>
 
<Calendar.Root
	value={myValue}
	onValueChange={(v) => {
		value = v.set({ hour: v.hour + 1 });
	}}
>
	<!-- ... -->
</Calendar.Root>

Use Cases

  • Implementing custom behaviors on value change
  • Integrating with external state management solutions
  • Triggering side effects (e.g., logging, data fetching)

3. Fully Controlled

For complete control over the component's value state, use the controlledValue prop. This approach requires you to manually manage the state, giving you full control over when and how the component responds to change events.

To implement controlled state:

  1. Set the controlledValue prop to true on the Calendar.Root component.
  2. Provide a value prop to Calendar.Root, which should be a variable holding the current state.
  3. Implement an onValueChange handler to update the state when the internal state changes.
	<script lang="ts">
	import { Calendar } from "bits-ui";
	let myValue = $state();
</script>
 
<Calendar.Root controlledValue value={myValue} onValueChange={(v) => (myValue = v)}>
	<!-- ... -->
</Calendar.Root>

When to Use

  • Implementing complex logic
  • Coordinating multiple UI elements
  • Debugging state-related issues

Default Value

Often, you'll want to start the Calendar.Root component with a default value. Likely this value will come from a database in the format of an ISO 8601 string.

You can use the parseDate function from the @internationalized/date package to parse the string into a CalendarDate object.

	<script lang="ts">
	import { Calendar } from "bits-ui";
	import { parseDate } from "@internationalized/date";
 
	// this came from a database/API call
	const date = "2024-08-03";
 
	let value = $state(parseDate(date));
</script>
 
<Calendar.Root {value}>
	<!-- ...-->
</Calendar.Root>

Validation

Minimum Value

You can set a minimum value for the calendar by using the minValue prop on Calendar.Root. If a user selects a date that is less than the minimum value, the calendar will be marked as invalid.

	<script lang="ts">
	import { Calendar } from "bits-ui";
	import { today, getLocalTimeZone } from "@internationalized/date";
 
	const todayDate = today(getLocalTimeZone());
	const yesterday = todayDate.subtract({ days: 1 });
</script>
 
<Calendar.Root minValue={todayDate} value={yesterday}>
	<!-- ...-->
</Calendar.Root>

Maximum Value

You can set a maximum value for the calendar by using the maxValue prop on Calendar.Root. If a user selects a date that is greater than the maximum value, the calendar will be marked as invalid.

	<script lang="ts">
	import { Calendar } from "bits-ui";
	import { today, getLocalTimeZone } from "@internationalized/date";
 
	const todayDate = today(getLocalTimeZone());
	const tomorrow = todayDate.add({ days: 1 });
</script>
 
<Calendar.Root maxValue={todayDate} value={tomorrow}>
	<!-- ...-->
</Calendar.Root>

Unavailable Dates

You can specify specific dates that are unavailable for selection by using the isDateUnavailable prop. This prop accepts a function that returns a boolean value indicating whether a date is unavailable or not.

	<script lang="ts">
	import { Calendar } from "bits-ui";
	import { today, getLocalTimeZone, isNotNull } from "@internationalized/date";
 
	const todayDate = today(getLocalTimeZone());
	const tomorrow = todayDate.add({ days: 1 });
 
	function isDateUnavailable(date: DateValue) {
		return date.day === 1;
	}
</script>
 
<Calendar.Root {isDateUnavailable} value={tomorrow}>
	<!-- ...-->
</Calendar.Root>

Disabled Dates

You can specify specific dates that are disabled for selection by using the isDateDisabled prop.

	<script lang="ts">
	import { Calendar } from "bits-ui";
	import { today, getLocalTimeZone, isNotNull } from "@internationalized/date";
 
	const todayDate = today(getLocalTimeZone());
	const tomorrow = todayDate.add({ days: 1 });
 
	function isDateDisabled(date: DateValue) {
		return date.day === 1;
	}
</script>
 
<Calendar.Root {isDateDisabled} value={tomorrow}>
	<!-- ...-->
</Calendar.Root>

Appearance & Behavior

Fixed Weeks

You can use the fixedWeeks prop to ensure that the calendar renders a fixed number of weeks, regardless of the number of days in the month. This is useful to keep the calendar visually consistent when the number of days in the month changes.

	<Calendar.Root fixedWeeks>
	<!-- ...-->
</Calendar.Root>

Multiple Months

You can use the numberOfMonths prop to render multiple months at once.

	<Calendar.Root numberOfMonths={2}>
	<!-- ...-->
</Calendar.Root>

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.

	<Calendar.Root pagedNavigation>
	<!-- ...-->
</Calendar.Root>

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 API.

	<Calendar.Root locale="fr-FR">
	<!-- ...-->
</Calendar.Root>

Week Starts On

The calendar will automatically format the content of the calendar according to the weekStartsOn prop, which defaults to 0, but can be changed to any day of the week, where 0 is Sunday and 6 is Saturday.

	<Calendar.Root weekStartsOn={1}>
	<!-- ...-->
</Calendar.Root>

Multiple Selection

You can set the type prop to 'multiple' to allow users to select multiple dates at once.

	<Calendar.Root type="multiple">
	<!-- ...-->
</Calendar.Root>

Custom Composition

Month Selector

The Calendar component includes a PrevButton and NextButton component to allow users to navigate between months. This is useful, but sometimes you may want to allow the user to select a specific month from a list of months, rather than having to navigate one at a time.

To achieve this, you can use the placeholder prop to set the month of the the calendar view programmatically.

	<script lang="ts">
	import { Calendar } from "bits-ui";
	import { CalendarDate } from "@internationalized/date";
 
	let placeholder = $state(new CalendarDate(2024, 8, 3));
</script>
 
<!-- You can use a select, button, or whatever you wish -->
<button
	onclick={() => {
		placeholder = placeholder.set({ month: 8 });
	}}
>
	Set month to August
</button>
 
<Calendar.Root bind:placeholder>
	<!-- ... -->
</Calendar.Root>

Updating the placeholder will update the calendar view to reflect the new month.

API Reference

Calendar.Root

The root calendar component which contains all other calendar components.

Property Type Description
type required
enum

Whether or not multiple dates can be selected.

Default: undefined
value $bindable
union

The selected date(s). If type is 'single', this will be a DateValue. If type is 'multiple', this will be an array of DateValues.

Default: undefined
onValueChange
function

A function that is called when the selected date changes.

Default: undefined
controlledValue
boolean

Whether or not the value is controlled or not. If true, the component will not update the value state internally, instead it will call onValueChange when it would have otherwise, and it is up to you to update the value prop that is passed to the component. See Controlled State for more information.

Default: false
placeholder
DateValue

The placeholder date, which is used to determine what month to display when no date is selected. This updates as the user navigates the calendar, and can be used to programmatically control the calendar's view.

Default: undefined
onPlaceholderChange
function

A function that is called when the placeholder date changes.

Default: undefined
controlledPlaceholder
boolean

Whether or not the placeholder is controlled or not. If true, the component will not update the placeholder state internally, instead it will call onPlaceholderChange when it would have otherwise, and it is up to you to update the placeholder prop that is passed to the component.

Default: false
pagedNavigation
boolean

Whether or not to use paged navigation for the calendar. Paged navigation causes the previous and next buttons to navigate by the number of months displayed at once, rather than by one month.

Default: false
preventDeselect
boolean

Whether or not to prevent the user from deselecting a date without selecting another date first.

Default: false
weekStartsOn
number

The day of the week to start the calendar on. 0 is Sunday, 1 is Monday, etc.

Default: 0
weekdayFormat
enum

The format to use for the weekday strings provided via the weekdays slot prop.

Default: 'narrow'
calendarLabel
string

The accessible label for the calendar.

Default: undefined
fixedWeeks
boolean

Whether or not to always display 6 weeks in the calendar.

Default: false
isDateDisabled
function

A function that returns whether or not a date is disabled.

Default: undefined
isDateUnavailable
function

A function that returns whether or not a date is unavailable.

Default: undefined
maxValue
DateValue

The maximum date that can be selected.

Default: undefined
minValue
DateValue

The minimum date that can be selected.

Default: undefined
locale
string

The locale to use for formatting dates.

Default: 'en'
numberOfMonths
number

The number of months to display at once.

Default: 1
disabled
boolean

Whether or not the accordion is disabled.

Default: false
readonly
boolean

Whether or not the calendar is readonly.

Default: false
initialFocus
boolean

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.

Default: false
disableDaysOutsideMonth
boolean

Whether or not to disable days outside the current month.

Default: false
ref $bindable
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined
Data Attribute Value Description
data-invalid
''

Present on the root element when the calendar is invalid.

data-disabled
''

Present on the root element when the calendar is disabled.

data-readonly
''

Present on the root element when the calendar is readonly.

data-calendar-root
''

Present on the root element.

Calendar.Header

The header of the calendar.

Property Type Description
ref $bindable
HTMLElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined
Data Attribute Value Description
data-disabled
''

Present on the header element when the calendar is disabled.

data-readonly
''

Present on the header element when the calendar is readonly.

data-calendar-header
''

Present on the header element.

Calendar.Heading

The heading of the calendar.

Property Type Description
ref $bindable
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined
Data Attribute Value Description
data-disabled
''

Present on the heading element when the calendar is disabled.

data-readonly
''

Present on the heading element when the calendar is readonly.

data-calendar-heading
''

Present on the heading element.

Calendar.NextButton

The next button of the calendar.

Property Type Description
ref $bindable
HTMLButtonElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined
Data Attribute Value Description
data-disabled
''

Present on the next button element when the calendar or this button is disabled.

data-calendar-next-button
''

Present on the next button element.

Calendar.PrevButton

The previous button of the calendar.

Property Type Description
ref $bindable
HTMLButtonElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined
Data Attribute Value Description
data-disabled
''

Present on the prev button element when the calendar or this button is disabled.

data-calendar-prev-button
''

Present on the prev button element.

Calendar.Cell

A cell in the calendar grid.

Property Type Description
date
DateValue

The date for the cell.

Default: undefined
month
DateValue

The current month the date is being displayed in.

Default: undefined
ref $bindable
HTMLTableCellElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined
Data Attribute Value Description
data-disabled
''

Present when the day is disabled.

data-unavailable
''

Present when the day is unavailable.

data-today
''

Present when the day is today.

data-outside-month
''

Present when the day is outside the current month.

data-outside-visible-months
''

Present when the day is outside the visible months.

data-focused
''

Present when the day is focused.

data-selected
''

Present when the day is selected.

data-value
''

The date in the format "YYYY-MM-DD".

data-calendar-cell
''

Present on the cell element.

Calendar.Day

A day in the calendar grid.

Property Type Description
ref $bindable
HTMLDivElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined
Data Attribute Value Description
data-disabled
''

Present when the day is disabled.

data-unavailable
''

Present when the day is unavailable.

data-today
''

Present when the day is today.

data-outside-month
''

Present when the day is outside the current month.

data-outside-visible-months
''

Present when the day is outside the visible months.

data-focused
''

Present when the day is focused.

data-selected
''

Present when the day is selected.

data-value
''

The date in the format "YYYY-MM-DD".

data-calendar-day
''

Present on the day element.

Calendar.Grid

The grid of dates in the calendar, typically representing a month.

Property Type Description
ref $bindable
HTMLTableElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined
Data Attribute Value Description
data-disabled
''

Present on the grid element when the calendar is disabled.

data-readonly
''

Present on the grid element when the calendar is readonly.

data-calendar-grid
''

Present on the grid element.

Calendar.GridBody

The body of the grid of dates in the calendar.

Property Type Description
ref $bindable
HTMLTableSectionElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined
Data Attribute Value Description
data-disabled
''

Present on the grid element when the calendar is disabled.

data-readonly
''

Present on the grid element when the calendar is readonly.

data-calendar-grid-body
''

Present on the grid body element.

Calendar.GridHead

The head of the grid of dates in the calendar.

Property Type Description
ref $bindable
HTMLTableSectionElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined
Data Attribute Value Description
data-disabled
''

Present on the grid head element when the calendar is disabled.

data-readonly
''

Present on the grid head element when the calendar is readonly.

data-calendar-grid-head
''

Present on the grid head element.

Calendar.GridRow

A row in the grid of dates in the calendar.

Property Type Description
ref $bindable
HTMLTableRowElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined
Data Attribute Value Description
data-disabled
''

Present on the grid row element when the calendar is disabled.

data-readonly
''

Present on the grid row element when the calendar is readonly.

data-calendar-grid-row
''

Present on the grid row element.

Calendar.HeadCell

A cell in the head of the grid of dates in the calendar.

Property Type Description
ref $bindable
HTMLTableCellElement

The underlying DOM element being rendered. You can bind to this to get a reference to the element.

Default: undefined
children
Snippet

The children content to render.

Default: undefined
child
Snippet

Use render delegation to render your own element. See Child Snippet docs for more information.

Default: undefined
Data Attribute Value Description
data-disabled
''

Present on the head cell element when the calendar is disabled.

data-readonly
''

Present on the head cell element when the calendar is readonly.

data-calendar-head-cell
''

Present on the head cell element.