| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
Selected: None
<script lang="ts">
import { DatePicker } from 'kumo-svelte';
let date = $state<Date | undefined>();
</script>
<div class="flex flex-col gap-4">
<DatePicker
mode="single"
selected={date}
onChange={(d) => {
if (d instanceof Date) {
date = d;
}
}}
/>
<p class="text-sm text-kumo-subtle">
Selected: {date ? date.toLocaleDateString() : 'None'}
</p>
</div> Installation
Barrel
import { DatePicker } from 'kumo-svelte'; Granular
import { DatePicker } from 'kumo-svelte/components/date-picker';Usage
DatePicker supports three selection modes: `single`, `multiple`, and `range`.
<script lang="ts"> import { DatePicker } from 'kumo-svelte'; let date = $state<Date | undefined>();</script><DatePicker mode="single" selected={date} onChange={(d) => (date = d as Date | undefined)} />Examples
Single Date Selection
Select a single date. The most common use case for date pickers.
| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
Selected: None
<script lang="ts">
import { DatePicker } from 'kumo-svelte';
let date = $state<Date | undefined>();
</script>
<div class="flex flex-col gap-4">
<DatePicker
mode="single"
selected={date}
onChange={(d) => {
if (d instanceof Date) {
date = d;
}
}}
/>
<p class="text-sm text-kumo-subtle">
Selected: {date ? date.toLocaleDateString() : 'None'}
</p>
</div> Multiple Date Selection
Select multiple individual dates. Use `max` to limit the number of selections.
| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
Selected: 0 date(s)
<script lang="ts">
import { DatePicker } from 'kumo-svelte';
let dates = $state<Date[] | undefined>();
</script>
<div class="flex flex-col gap-4">
<DatePicker
mode="multiple"
selected={dates}
onChange={(d) => (dates = d as Date[] | undefined)}
max={5}
/>
<p class="text-sm text-kumo-subtle">
Selected: {dates?.length ?? 0} date(s)
</p>
</div> Date Range Selection
Select a continuous range of dates. Works well with `numberOfMonths=2` for a side-by-side view.
| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
Range: None
<script lang="ts">
import { DatePicker, type DateRange } from 'kumo-svelte';
let range = $state<DateRange | undefined>();
</script>
<div class="flex flex-col gap-4">
<DatePicker
mode="range"
selected={range}
onChange={(d) => (range = d as DateRange | undefined)}
numberOfMonths={2}
/>
<p class="text-sm text-kumo-subtle">
Range: {range?.from
? `${range.from.toLocaleDateString()} - ${range.to?.toLocaleDateString() ?? '...'}`
: 'None'}
</p>
</div> Range with Min/Max Constraints
Constrain the range length using `min` and `max` props (in days/nights).
| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
<script lang="ts">
import { DatePicker, type DateRange } from 'kumo-svelte';
let range = $state<DateRange | undefined>();
</script>
{#snippet footer()}
<span class="text-xs text-kumo-subtle">Select 3-7 nights</span>
{/snippet}
<div class="flex flex-col gap-4">
<DatePicker
mode="range"
selected={range}
onChange={(d) => (range = d as DateRange | undefined)}
min={3}
max={7}
{footer}
/>
</div> With Popover
Compose with the [Popover](/components/popover) component to create a dropdown date picker.
<script lang="ts">
import { Button, DatePicker, Popover } from 'kumo-svelte';
import { CalendarDotsIcon } from 'phosphor-svelte';
let date = $state<Date | undefined>();
</script>
<Popover class="p-3">
{#snippet trigger(props)}
<Button variant="outline" icon={CalendarDotsIcon} {...props}>
{date ? date.toLocaleDateString() : 'Pick a date'}
</Button>
{/snippet}
<DatePicker mode="single" selected={date} onChange={(d) => (date = d as Date | undefined)} />
</Popover> Date Range with Popover
A date range picker in a popover with two months displayed.
<script lang="ts">
import { Button, DatePicker, Popover, type DateRange } from 'kumo-svelte';
import { CalendarDotsIcon } from 'phosphor-svelte';
let range = $state<DateRange | undefined>();
function formatRange() {
if (!range?.from) return 'Select dates';
if (!range.to) return range.from.toLocaleDateString();
return `${range.from.toLocaleDateString()} - ${range.to.toLocaleDateString()}`;
}
</script>
<Popover class="p-3">
{#snippet trigger(props)}
<Button variant="outline" icon={CalendarDotsIcon} {...props}>
{formatRange()}
</Button>
{/snippet}
<DatePicker
mode="range"
selected={range}
onChange={(d) => (range = d as DateRange | undefined)}
numberOfMonths={2}
/>
</Popover> Date Range with Presets
Combine the date picker with preset options for quick selection.
<script lang="ts">
import { Button, DatePicker, Popover, type DateRange } from 'kumo-svelte';
import { CalendarDotsIcon } from 'phosphor-svelte';
let range = $state<DateRange | undefined>();
let month = $state(new Date());
const today = new Date();
const presets = [
{ label: 'Today', range: { from: today, to: today } },
{
label: 'Last 7 days',
range: { from: new Date(today.getTime() - 6 * 24 * 60 * 60 * 1000), to: today }
},
{
label: 'Last 30 days',
range: { from: new Date(today.getTime() - 29 * 24 * 60 * 60 * 1000), to: today }
},
{
label: 'Last 90 days',
range: { from: new Date(today.getTime() - 89 * 24 * 60 * 60 * 1000), to: today }
},
{
label: 'This month',
range: { from: new Date(today.getFullYear(), today.getMonth(), 1), to: new Date(today.getFullYear(), today.getMonth() + 1, 0) }
},
{
label: 'Last month',
range: { from: new Date(today.getFullYear(), today.getMonth() - 1, 1), to: new Date(today.getFullYear(), today.getMonth(), 0) }
}
];
function formatRange() {
if (!range?.from) return 'Select dates';
if (!range.to) return range.from.toLocaleDateString();
return `${range.from.toLocaleDateString()} - ${range.to.toLocaleDateString()}`;
}
function handlePresetClick(preset: { range: DateRange }) {
range = preset.range;
if (preset.range.from) month = preset.range.from;
}
function isPresetActive(preset: { range: DateRange }) {
if (!range?.from || !range?.to || !preset.range.from || !preset.range.to) return false;
return range.from.toDateString() === preset.range.from.toDateString()
&& range.to.toDateString() === preset.range.to.toDateString();
}
</script>
<Popover class="p-0">
{#snippet trigger(props)}
<Button variant="outline" icon={CalendarDotsIcon} {...props}>{formatRange()}</Button>
{/snippet}
<div class="flex">
<div class="flex flex-col gap-1 border-r border-kumo-hairline p-2 text-sm">
{#each presets as preset (preset.label)}
<button
type="button"
onclick={() => handlePresetClick(preset)}
class={isPresetActive(preset)
? 'rounded-md bg-kumo-bg-inverse px-3 py-1.5 text-left whitespace-nowrap text-kumo-text-inverse'
: 'rounded-md px-3 py-1.5 text-left whitespace-nowrap text-kumo-subtle hover:bg-kumo-control'}
>
{preset.label}
</button>
{/each}
</div>
<div class="p-3">
<DatePicker
mode="range"
selected={range}
onChange={(d) => (range = d as DateRange | undefined)}
bind:month
numberOfMonths={2}
/>
</div>
</div>
</Popover> Disabled Dates with Usage Limits
Use the `disabled` prop to make certain dates unselectable, and `footer` to display usage information.
| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
<script lang="ts">
import { DatePicker } from 'kumo-svelte';
let dates = $state<Date[] | undefined>();
const today = new Date();
const maxDays = 5;
const unavailableDates = [
new Date(today.getFullYear(), today.getMonth(), 5),
new Date(today.getFullYear(), today.getMonth(), 12),
new Date(today.getFullYear(), today.getMonth(), 18),
new Date(today.getFullYear(), today.getMonth(), 25)
];
</script>
{#snippet footer()}
<p class="w-full pt-2 text-xs text-kumo-subtle">
{dates?.length ?? 0}/{maxDays} days selected. Grayed dates are unavailable.
</p>
{/snippet}
<DatePicker
mode="multiple"
selected={dates}
onChange={(d) => (dates = d as Date[] | undefined)}
max={maxDays}
disabled={unavailableDates}
fixedWeeks
{footer}
/> Full Popover Example
Here's a complete example showing how to compose DatePicker with Popover:
<script lang="ts"> import { Button, DatePicker, Popover } from 'kumo-svelte'; import { CalendarDotsIcon } from 'phosphor-svelte'; let date = $state<Date | undefined>();</script><Popover class="p-3"> {#snippet trigger(props)} <Button variant="outline" icon={CalendarDotsIcon} {...props}> {date ? date.toLocaleDateString() : 'Pick a date'} </Button> {/snippet} <DatePicker mode="single" selected={date} onChange={(d) => (date = d as Date | undefined)} /></Popover>API Reference
DatePicker mirrors the original Kumo calendar API. Key props include:
- `mode` —
"single" | "multiple" | "range"— Selection mode (required) - `selected` — Currently selected date(s)
- `onChange` — Callback when selection changes
- `numberOfMonths` — Number of months to display
- `disabled` — Dates that cannot be selected
- `min` / `max` — Min/max selection constraints
- `footer` — Content rendered below the calendar
- `locale` — Locale string for internationalization
- `className` — Additional CSS classes
See the react-day-picker documentation for the full upstream API.
Differences from react-day-picker
For consistency with other Kumo form components, DatePicker uses `onChange` instead of react-day-picker's `onSelect`.