Calendar
A month grid for picking one date, several dates, or a range. Use it on its own in a form, or inside a popover as a date picker.
| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
Monday, October 12, 2026
Usage
import { useState } from "react";
import { Calendar } from "@tulipfarm/sprout/calendar";
const [date, setDate] = useState<Date | undefined>(new Date(2026, 9, 12));
<Calendar
mode="single"
selected={date}
onSelect={setDate}
defaultMonth={new Date(2026, 9, 1)}
/>Calendar wraps React DayPicker 10 and takes all of its props. Sprõut adds its own styles, Sprõut buttons for month navigation, and Sprõut selects for the month and year menus.
Selection modes
Set mode to "single", "range", or "multiple", and control the value with selected and onSelect. A range passes { from, to }; the first and last days are filled and the days between share a band. Pass a matcher to disabled, such as { dayOfWeek: [0, 6] } for weekends.
Selection modes
Click a selected date again to clear it. Weekends are disabled in the multiple-date calendar.
| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
Monday, October 12, 2026
| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
Oct 12 – Oct 16
| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
Oct 13, Oct 15
Captions and navigation
captionLayout="label" (default) shows the month name. "dropdown" shows month and year menus; "dropdown-months" and "dropdown-years" show one. buttonVariant picks the Button variant for the previous and next buttons: "ghost" (default) or "outline".
Captions and navigation
Month and year menus are Sprõut selects, never native ones. Years run from 100 years ago to this year.
| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
Date picker
Put the calendar straight inside PopoverContent. It fills the panel and drops its own surface. Close the popover in onSelect and ignore undefined so clicking the chosen day again doesn’t clear it.
<Popover open={open} onOpenChange={setOpen}>
<h2 aria-label={title}>
<PopoverTrigger
render={<Button variant="ghost" size="calendar-title" aria-label="Choose date" />}
>
{title}
<ChevronDown size={14} aria-hidden="true" />
</PopoverTrigger>
</h2>
<PopoverContent align="start" aria-label="Choose a calendar date">
<Calendar
mode="single"
weekStartsOn={1}
selected={day}
defaultMonth={day}
onSelect={(date) => {
if (date) {
setOpen(false);
show(date);
}
}}
/>
</PopoverContent>
</Popover>Date picker
The calendar page opens a Monday-first calendar from its month title. Picking a date closes the popover and moves the view.
Showing the week of Monday, October 19, 2026.
Layout and custom days
numberOfMonths shows months side by side from 768px and stacked below. showWeekNumber adds a week column, and weekStartsOn sets the first weekday. To add content under a date, render CalendarDayButton from components.DayButton and put the extra content in a span. Set --sprout-calendar-cell to make room.
Layout and custom days
Show week numbers and two months for longer ranges. Add content under each date with CalendarDayButton.
| Mo | Tu | We | Th | Fr | Sa | Su | |
|---|---|---|---|---|---|---|---|
40 | |||||||
41 | |||||||
42 | |||||||
43 | |||||||
44 |
| Mo | Tu | We | Th | Fr | Sa | Su | |
|---|---|---|---|---|---|---|---|
44 | |||||||
45 | |||||||
46 | |||||||
47 | |||||||
48 | |||||||
49 |
Oct 26 – Nov 6
| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
Monday, October 12, 2026 · 3 events
API
Calendar takes every React DayPicker prop. Sprõut sets showOutsideDays to true and captionLayout to "label", and adds buttonVariant ("ghost"). Your classNames, formatters, and components merge over Sprõut’s. The root has data-slot="calendar".
CalendarDayButton is the day button. It takes the DayPicker day button props and sets data-selected-single, data-range-start, data-range-middle, data-range-end, and data-day. The package also exports the DateRange and Matcher types.
Accessibility
The month is a labelled grid. Tab moves to the selected day, or today. Arrow keys move by day and week, Home and End go to the start and end of the week, Page Up and Page Down change month, and Shift with Page Up or Page Down changes year. Enter or Space selects. Disabled days stay readable but can’t be chosen.
Day colors change over 120ms, with no motion when reduced motion is requested. In forced-colors mode selected days keep an outline.
Theme tokens
Selected days use --sprout-primary and --sprout-on-primary, so they follow the TulipFarm brand when you opt in. Today and range bands use --sprout-hover; muted text uses --sprout-muted. Set --sprout-calendar-cell (1.75rem) and --sprout-calendar-radius on the calendar to resize it.