Building Blocks for the Web
Clean, modern building blocks. Copy and paste into your apps. Works with all React frameworks. Open Source. Free forever.
Files
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar01() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} defaultValue={date} />
</div>
)
}
A simple calendar.
calendar-01
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar01() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} defaultValue={date} />
</div>
)
}
Files
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar02() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} />
</div>
)
}
Multiple months with single selection.
calendar-02
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar02() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} />
</div>
)
}
Files
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar03() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} />
</div>
)
}
Multiple months with multiple selection.
calendar-03
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar03() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} />
</div>
)
}
Files
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import type { RangeValue } from "react-aria-components"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar04() {
const [dateRange, setDateRange] = React.useState<RangeValue<CalendarDate>>(
() => ({
start: parseDate("2025-06-09"),
end: parseDate("2025-06-26"),
})
)
return (
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar value={dateRange} onChange={setDateRange} />
</div>
)
}
Single month with range selection
calendar-04
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import type { RangeValue } from "react-aria-components"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar04() {
const [dateRange, setDateRange] = React.useState<RangeValue<CalendarDate>>(
() => ({
start: parseDate("2025-06-09"),
end: parseDate("2025-06-26"),
})
)
return (
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar value={dateRange} onChange={setDateRange} />
</div>
)
}
Files
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import type { RangeValue } from "react-aria-components"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar05() {
const [dateRange, setDateRange] = React.useState<RangeValue<CalendarDate>>(
() => ({
start: parseDate("2025-06-12"),
end: parseDate("2025-07-15"),
})
)
return (
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={dateRange}
onChange={setDateRange}
visibleDuration={{ months: 2 }}
/>
</div>
)
}
Multiple months with range selection
calendar-05
June to July 2025
June – July 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
29 | 30 | 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 |
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import type { RangeValue } from "react-aria-components"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar05() {
const [dateRange, setDateRange] = React.useState<RangeValue<CalendarDate>>(
() => ({
start: parseDate("2025-06-12"),
end: parseDate("2025-07-15"),
})
)
return (
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={dateRange}
onChange={setDateRange}
visibleDuration={{ months: 2 }}
/>
</div>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { getLocalTimeZone, parseDate } from "@internationalized/date"
import type { RangeValue } from "react-aria-components"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar06() {
const [range, setRange] = React.useState<RangeValue<CalendarDate>>(() => ({
start: parseDate("2025-06-12"),
end: parseDate("2025-06-26"),
}))
const getNights = (value: RangeValue<CalendarDate>) => {
if (!value || !value.start || !value.end) return 0
const tz = getLocalTimeZone()
const start = value.start.toDate(tz)
const end = value.end.toDate(tz)
return Math.max(0, Math.round((end.getTime() - start.getTime()) / 86400000))
}
const nights = getNights(range)
return (
<div className="flex min-w-0 flex-col gap-2">
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={range}
onChange={setRange}
errorMessage={
nights > 0 && nights < 5
? "A minimum of 5 days is required"
: undefined
}
/>
</div>
<div className="text-muted-foreground text-center text-xs">
A minimum of 5 days is required
</div>
</div>
)
}
Range selection with minimum days
calendar-06
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
A minimum of 5 days is required
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { getLocalTimeZone, parseDate } from "@internationalized/date"
import type { RangeValue } from "react-aria-components"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar06() {
const [range, setRange] = React.useState<RangeValue<CalendarDate>>(() => ({
start: parseDate("2025-06-12"),
end: parseDate("2025-06-26"),
}))
const getNights = (value: RangeValue<CalendarDate>) => {
if (!value || !value.start || !value.end) return 0
const tz = getLocalTimeZone()
const start = value.start.toDate(tz)
const end = value.end.toDate(tz)
return Math.max(0, Math.round((end.getTime() - start.getTime()) / 86400000))
}
const nights = getNights(range)
return (
<div className="flex min-w-0 flex-col gap-2">
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={range}
onChange={setRange}
errorMessage={
nights > 0 && nights < 5
? "A minimum of 5 days is required"
: undefined
}
/>
</div>
<div className="text-muted-foreground text-center text-xs">
A minimum of 5 days is required
</div>
</div>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { getLocalTimeZone, parseDate } from "@internationalized/date"
import type { RangeValue } from "react-aria-components"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar07() {
const [range, setRange] = React.useState<RangeValue<CalendarDate>>(() => ({
start: parseDate("2025-06-18"),
end: parseDate("2025-07-07"),
}))
const getNights = (value: RangeValue<CalendarDate>) => {
if (!value || !value.start || !value.end) return 0
const tz = getLocalTimeZone()
const start = value.start.toDate(tz)
const end = value.end.toDate(tz)
return Math.max(0, Math.round((end.getTime() - start.getTime()) / 86400000))
}
const nights = getNights(range)
return (
<div className="flex min-w-0 flex-col gap-2">
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={range}
onChange={setRange}
visibleDuration={{ months: 2 }}
errorMessage={
nights > 0 && (nights < 2 || nights > 20)
? "Your stay must be between 2 and 20 nights"
: undefined
}
/>
</div>
<div className="text-muted-foreground text-center text-xs">
Your stay must be between 2 and 20 nights
</div>
</div>
)
}
Range selection with minimum and maximum days
calendar-07
June to July 2025
June – July 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
29 | 30 | 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 |
Your stay must be between 2 and 20 nights
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { getLocalTimeZone, parseDate } from "@internationalized/date"
import type { RangeValue } from "react-aria-components"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar07() {
const [range, setRange] = React.useState<RangeValue<CalendarDate>>(() => ({
start: parseDate("2025-06-18"),
end: parseDate("2025-07-07"),
}))
const getNights = (value: RangeValue<CalendarDate>) => {
if (!value || !value.start || !value.end) return 0
const tz = getLocalTimeZone()
const start = value.start.toDate(tz)
const end = value.end.toDate(tz)
return Math.max(0, Math.round((end.getTime() - start.getTime()) / 86400000))
}
const nights = getNights(range)
return (
<div className="flex min-w-0 flex-col gap-2">
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={range}
onChange={setRange}
visibleDuration={{ months: 2 }}
errorMessage={
nights > 0 && (nights < 2 || nights > 20)
? "Your stay must be between 2 and 20 nights"
: undefined
}
/>
</div>
<div className="text-muted-foreground text-center text-xs">
Your stay must be between 2 and 20 nights
</div>
</div>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar08() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={setDate}
minValue={parseDate("2025-06-12")}
/>
</div>
)
}
Calendar with disabled days
calendar-08
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar08() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={setDate}
minValue={parseDate("2025-06-12")}
/>
</div>
)
}
Files
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import type { RangeValue } from "react-aria-components"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar09() {
const [range, setRange] = React.useState<RangeValue<CalendarDate>>(() => ({
start: parseDate("2025-06-17"),
end: parseDate("2025-06-20"),
}))
const isWeekend = (d: CalendarDate) => d.dayOfWeek === 0 || d.dayOfWeek === 6
return (
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={range}
onChange={setRange}
visibleDuration={{ months: 2 }}
isDateUnavailable={isWeekend}
/>
</div>
)
}
Calendar with disabled weekends
calendar-09
June to July 2025
June – July 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
29 | 30 | 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 |
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import type { RangeValue } from "react-aria-components"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar09() {
const [range, setRange] = React.useState<RangeValue<CalendarDate>>(() => ({
start: parseDate("2025-06-17"),
end: parseDate("2025-06-20"),
}))
const isWeekend = (d: CalendarDate) => d.dayOfWeek === 0 || d.dayOfWeek === 6
return (
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={range}
onChange={setRange}
visibleDuration={{ months: 2 }}
isDateUnavailable={isWeekend}
/>
</div>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { getLocalTimeZone, parseDate, today } from "@internationalized/date"
import { Button } from "@/components/ui/button"
import {
Card,
CardAction,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar10() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<Card>
<CardHeader>
<CardTitle>Appointment</CardTitle>
<CardDescription>Find a date</CardDescription>
<CardAction>
<Button
size="sm"
variant="outline"
onClick={() => {
setDate(today(getLocalTimeZone()))
}}
>
Today
</Button>
</CardAction>
</CardHeader>
<CardContent>
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} />
</div>
</CardContent>
</Card>
)
}
Today button
calendar-10
Appointment
Find a date
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { getLocalTimeZone, parseDate, today } from "@internationalized/date"
import { Button } from "@/components/ui/button"
import {
Card,
CardAction,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar10() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<Card>
<CardHeader>
<CardTitle>Appointment</CardTitle>
<CardDescription>Find a date</CardDescription>
<CardAction>
<Button
size="sm"
variant="outline"
onClick={() => {
setDate(today(getLocalTimeZone()))
}}
>
Today
</Button>
</CardAction>
</CardHeader>
<CardContent>
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} />
</div>
</CardContent>
</Card>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import type { RangeValue } from "react-aria-components"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar11() {
const [range, setRange] = React.useState<RangeValue<CalendarDate>>(() => ({
start: parseDate("2025-06-17"),
end: parseDate("2025-06-20"),
}))
return (
<div className="flex min-w-0 flex-col gap-2">
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={range}
onChange={setRange}
visibleDuration={{ months: 2 }}
minValue={parseDate("2025-06-01")}
maxValue={parseDate("2025-07-31")}
/>
</div>
<div className="text-muted-foreground text-center text-xs">
We are open in June and July only.
</div>
</div>
)
}
Start and end of month
calendar-11
June to July 2025
June – July 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
29 | 30 | 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 |
We are open in June and July only.
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import type { RangeValue } from "react-aria-components"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar11() {
const [range, setRange] = React.useState<RangeValue<CalendarDate>>(() => ({
start: parseDate("2025-06-17"),
end: parseDate("2025-06-20"),
}))
return (
<div className="flex min-w-0 flex-col gap-2">
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={range}
onChange={setRange}
visibleDuration={{ months: 2 }}
minValue={parseDate("2025-06-01")}
maxValue={parseDate("2025-07-31")}
/>
</div>
<div className="text-muted-foreground text-center text-xs">
We are open in June and July only.
</div>
</div>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { I18nProvider } from "@react-aria/i18n"
import type { RangeValue } from "react-aria-components"
import {
Card,
CardAction,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
const localizedStrings = {
en: {
title: "Book an appointment",
description: "Select the dates for your appointment",
},
es: {
title: "Reserva una cita",
description: "Selecciona las fechas para tu cita",
},
} as const
export function Calendar12() {
const [locale, setLocale] =
React.useState<keyof typeof localizedStrings>("es")
const [range, setRange] = React.useState<RangeValue<CalendarDate>>(() => ({
start: parseDate("2025-09-09"),
end: parseDate("2025-09-17"),
}))
return (
<Card>
<CardHeader className="border-b">
<CardTitle>{localizedStrings[locale].title}</CardTitle>
<CardDescription>
{localizedStrings[locale].description}
</CardDescription>
<CardAction>
<Select
value={locale}
onValueChange={(value) =>
setLocale(value as keyof typeof localizedStrings)
}
>
<SelectTrigger className="w-[100px]">
<SelectValue placeholder="Language" />
</SelectTrigger>
<SelectContent align="end">
<SelectItem value="es">Español</SelectItem>
<SelectItem value="en">English</SelectItem>
</SelectContent>
</Select>
</CardAction>
</CardHeader>
<CardContent>
<I18nProvider locale={locale === "es" ? "es-ES" : "en-US"}>
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={range}
onChange={setRange}
visibleDuration={{ months: 2 }}
/>
</div>
</I18nProvider>
</CardContent>
</Card>
)
}
Localized calendar
calendar-12
Reserva una cita
Selecciona las fechas para tu cita
septiembre a octubre de 2025
septiembre–octubre de 2025
L | M | X | J | V | S | D |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
L | M | X | J | V | S | D |
---|---|---|---|---|---|---|
29 | 30 | 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 |
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { I18nProvider } from "@react-aria/i18n"
import type { RangeValue } from "react-aria-components"
import {
Card,
CardAction,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
const localizedStrings = {
en: {
title: "Book an appointment",
description: "Select the dates for your appointment",
},
es: {
title: "Reserva una cita",
description: "Selecciona las fechas para tu cita",
},
} as const
export function Calendar12() {
const [locale, setLocale] =
React.useState<keyof typeof localizedStrings>("es")
const [range, setRange] = React.useState<RangeValue<CalendarDate>>(() => ({
start: parseDate("2025-09-09"),
end: parseDate("2025-09-17"),
}))
return (
<Card>
<CardHeader className="border-b">
<CardTitle>{localizedStrings[locale].title}</CardTitle>
<CardDescription>
{localizedStrings[locale].description}
</CardDescription>
<CardAction>
<Select
value={locale}
onValueChange={(value) =>
setLocale(value as keyof typeof localizedStrings)
}
>
<SelectTrigger className="w-[100px]">
<SelectValue placeholder="Language" />
</SelectTrigger>
<SelectContent align="end">
<SelectItem value="es">Español</SelectItem>
<SelectItem value="en">English</SelectItem>
</SelectContent>
</Select>
</CardAction>
</CardHeader>
<CardContent>
<I18nProvider locale={locale === "es" ? "es-ES" : "en-US"}>
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={range}
onChange={setRange}
visibleDuration={{ months: 2 }}
/>
</div>
</I18nProvider>
</CardContent>
</Card>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { Label } from "@/components/ui/label"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
export function Calendar13() {
// Caption layout modes are not supported by Preskok UI calendar.
// We keep the dropdown UI as a no-op to demonstrate available options.
const [dropdown, setDropdown] = React.useState<
"dropdown" | "dropdown-months" | "dropdown-years"
>("dropdown")
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<div className="flex flex-col gap-4">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} />
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="dropdown" className="px-1">
Dropdown
</Label>
<Select
value={dropdown}
onValueChange={(value) =>
setDropdown(
value as React.ComponentProps<typeof Calendar>["captionLayout"]
)
}
>
<SelectTrigger
id="dropdown"
size="sm"
className="bg-background w-full"
>
<SelectValue placeholder="Dropdown" />
</SelectTrigger>
<SelectContent align="center">
<SelectItem value="dropdown">Month and Year</SelectItem>
<SelectItem value="dropdown-months">Month Only</SelectItem>
<SelectItem value="dropdown-years">Year Only</SelectItem>
</SelectContent>
</Select>
</div>
</div>
)
}
With Month and Year Dropdown
calendar-13
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { Label } from "@/components/ui/label"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
export function Calendar13() {
// Caption layout modes are not supported by Preskok UI calendar.
// We keep the dropdown UI as a no-op to demonstrate available options.
const [dropdown, setDropdown] = React.useState<
"dropdown" | "dropdown-months" | "dropdown-years"
>("dropdown")
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<div className="flex flex-col gap-4">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} />
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="dropdown" className="px-1">
Dropdown
</Label>
<Select
value={dropdown}
onValueChange={(value) =>
setDropdown(
value as React.ComponentProps<typeof Calendar>["captionLayout"]
)
}
>
<SelectTrigger
id="dropdown"
size="sm"
className="bg-background w-full"
>
<SelectValue placeholder="Dropdown" />
</SelectTrigger>
<SelectContent align="center">
<SelectItem value="dropdown">Month and Year</SelectItem>
<SelectItem value="dropdown-months">Month Only</SelectItem>
<SelectItem value="dropdown-years">Year Only</SelectItem>
</SelectContent>
</Select>
</div>
</div>
)
}
Files
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar14() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
const pad2 = (n: number) => String(n).padStart(2, "0")
const bookedDateKeys = new Set(
Array.from({ length: 12 }, (_, i) => `2025-06-${pad2(15 + i)}`)
)
const isBooked = (d: CalendarDate) =>
bookedDateKeys.has(`${d.year}-${pad2(d.month)}-${pad2(d.day)}`)
return (
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} isDateUnavailable={isBooked} />
</div>
)
}
With Booked/Unavailable Days
calendar-14
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar14() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
const pad2 = (n: number) => String(n).padStart(2, "0")
const bookedDateKeys = new Set(
Array.from({ length: 12 }, (_, i) => `2025-06-${pad2(15 + i)}`)
)
const isBooked = (d: CalendarDate) =>
bookedDateKeys.has(`${d.year}-${pad2(d.month)}-${pad2(d.day)}`)
return (
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} isDateUnavailable={isBooked} />
</div>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar15() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<div className="inline-block rounded-lg border shadow-sm">
{/* Week numbers are not supported by Preskok UI calendar */}
<Calendar value={date} onChange={setDate} />
</div>
)
}
With Week Numbers
calendar-15
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar15() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<div className="inline-block rounded-lg border shadow-sm">
{/* Week numbers are not supported by Preskok UI calendar */}
<Calendar value={date} onChange={setDate} />
</div>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { Clock2Icon } from "lucide-react"
import { Card, CardContent, CardFooter } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar16() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<Card className="w-fit py-4">
<CardContent className="px-4">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} />
</div>
</CardContent>
<CardFooter className="flex flex-col gap-6 border-t px-4 !pt-4">
<div className="flex w-full flex-col gap-3">
<Label htmlFor="time-from">Start Time</Label>
<div className="relative flex w-full items-center gap-2">
<Clock2Icon className="text-muted-foreground pointer-events-none absolute left-2.5 size-4 select-none" />
<Input
id="time-from"
type="time"
step="1"
defaultValue="10:30:00"
className="appearance-none pl-8 [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
</div>
<div className="flex w-full flex-col gap-3">
<Label htmlFor="time-to">End Time</Label>
<div className="relative flex w-full items-center gap-2">
<Clock2Icon className="text-muted-foreground pointer-events-none absolute left-2.5 size-4 select-none" />
<Input
id="time-to"
type="time"
step="1"
defaultValue="12:30:00"
className="appearance-none pl-8 [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
</div>
</CardFooter>
</Card>
)
}
With time picker
calendar-16
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { Clock2Icon } from "lucide-react"
import { Card, CardContent, CardFooter } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar16() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<Card className="w-fit py-4">
<CardContent className="px-4">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} />
</div>
</CardContent>
<CardFooter className="flex flex-col gap-6 border-t px-4 !pt-4">
<div className="flex w-full flex-col gap-3">
<Label htmlFor="time-from">Start Time</Label>
<div className="relative flex w-full items-center gap-2">
<Clock2Icon className="text-muted-foreground pointer-events-none absolute left-2.5 size-4 select-none" />
<Input
id="time-from"
type="time"
step="1"
defaultValue="10:30:00"
className="appearance-none pl-8 [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
</div>
<div className="flex w-full flex-col gap-3">
<Label htmlFor="time-to">End Time</Label>
<div className="relative flex w-full items-center gap-2">
<Clock2Icon className="text-muted-foreground pointer-events-none absolute left-2.5 size-4 select-none" />
<Input
id="time-to"
type="time"
step="1"
defaultValue="12:30:00"
className="appearance-none pl-8 [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
</div>
</CardFooter>
</Card>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { Card, CardContent, CardFooter } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar17() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<Card className="w-fit py-4">
<CardContent className="px-4">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={setDate}
className="[--cell-size:--spacing(10.5)]"
/>
</div>
</CardContent>
<CardFooter className="flex gap-2 border-t px-4 !pt-4 *:[div]:w-full">
<div>
<Label htmlFor="time-from" className="sr-only">
Start Time
</Label>
<Input
id="time-from"
type="time"
step="1"
defaultValue="10:30:00"
className="appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
<span>-</span>
<div>
<Label htmlFor="time-to" className="sr-only">
End Time
</Label>
<Input
id="time-to"
type="time"
step="1"
defaultValue="12:30:00"
className="appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
</CardFooter>
</Card>
)
}
With time picker inline
calendar-17
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
-
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { Card, CardContent, CardFooter } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar17() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<Card className="w-fit py-4">
<CardContent className="px-4">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={setDate}
className="[--cell-size:--spacing(10.5)]"
/>
</div>
</CardContent>
<CardFooter className="flex gap-2 border-t px-4 !pt-4 *:[div]:w-full">
<div>
<Label htmlFor="time-from" className="sr-only">
Start Time
</Label>
<Input
id="time-from"
type="time"
step="1"
defaultValue="10:30:00"
className="appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
<span>-</span>
<div>
<Label htmlFor="time-to" className="sr-only">
End Time
</Label>
<Input
id="time-to"
type="time"
step="1"
defaultValue="12:30:00"
className="appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
</CardFooter>
</Card>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar18() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={setDate}
className="[--cell-size:--spacing(11)] md:[--cell-size:--spacing(12)]"
/>
</div>
)
}
Variable size
calendar-18
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar18() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={setDate}
className="[--cell-size:--spacing(11)] md:[--cell-size:--spacing(12)]"
/>
</div>
)
}
Files
"use client"
import * as React from "react"
import { getLocalTimeZone, parseDate, today } from "@internationalized/date"
import type { CalendarDate } from "@internationalized/date"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardFooter } from "@/components/ui/card"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar19() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<Card className="max-w-[300px] py-4">
<CardContent className="px-4">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={setDate}
className="[--cell-size:--spacing(9.5)]"
/>
</div>
</CardContent>
<CardFooter className="flex flex-wrap gap-2 border-t px-4 !pt-4">
{[
{ label: "Today", value: 0 },
{ label: "Tomorrow", value: 1 },
{ label: "In 3 days", value: 3 },
{ label: "In a week", value: 7 },
{ label: "In 2 weeks", value: 14 },
].map((preset) => (
<Button
key={preset.value}
variant="outline"
size="sm"
className="flex-1"
onClick={() => {
const base = today(getLocalTimeZone())
setDate(base.add({ days: preset.value }))
}}
>
{preset.label}
</Button>
))}
</CardFooter>
</Card>
)
}
With presets
calendar-19
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
"use client"
import * as React from "react"
import { getLocalTimeZone, parseDate, today } from "@internationalized/date"
import type { CalendarDate } from "@internationalized/date"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardFooter } from "@/components/ui/card"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar19() {
const [date, setDate] = React.useState<CalendarDate>(() =>
parseDate("2025-06-12")
)
return (
<Card className="max-w-[300px] py-4">
<CardContent className="px-4">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={setDate}
className="[--cell-size:--spacing(9.5)]"
/>
</div>
</CardContent>
<CardFooter className="flex flex-wrap gap-2 border-t px-4 !pt-4">
{[
{ label: "Today", value: 0 },
{ label: "Tomorrow", value: 1 },
{ label: "In 3 days", value: 3 },
{ label: "In a week", value: 7 },
{ label: "In 2 weeks", value: 14 },
].map((preset) => (
<Button
key={preset.value}
variant="outline"
size="sm"
className="flex-1"
onClick={() => {
const base = today(getLocalTimeZone())
setDate(base.add({ days: preset.value }))
}}
>
{preset.label}
</Button>
))}
</CardFooter>
</Card>
)
}
Files
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardFooter } from "@/components/ui/card"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar20() {
const [date, setDate] = React.useState<CalendarDate | undefined>(() =>
parseDate("2025-06-12")
)
const [selectedTime, setSelectedTime] = React.useState<string | null>("10:00")
const timeSlots = Array.from({ length: 37 }, (_, i) => {
const totalMinutes = i * 15
const hour = Math.floor(totalMinutes / 60) + 9
const minute = totalMinutes % 60
return `${hour.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}`
})
const bookedDates = new Set(
Array.from({ length: 3 }, (_, i) =>
parseDate(`2025-06-${(17 + i).toString().padStart(2, "0")}`)
)
)
const isBooked = (d: CalendarDate) =>
bookedDates.has(
parseDate(
`${d.year}-${String(d.month).padStart(2, "0")}-${String(d.day).padStart(2, "0")}`
)
)
return (
<Card className="gap-0 p-0">
<CardContent className="relative p-0 md:pr-48">
<div className="p-6">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={setDate}
isDateUnavailable={isBooked}
className="[--cell-size:--spacing(10)] md:[--cell-size:--spacing(12)]"
/>
</div>
</div>
<div className="no-scrollbar inset-y-0 right-0 flex max-h-72 w-full scroll-pb-6 flex-col gap-4 overflow-y-auto border-t p-6 md:absolute md:max-h-none md:w-48 md:border-t-0 md:border-l">
<div className="grid gap-2">
{timeSlots.map((time) => (
<Button
key={time}
variant={selectedTime === time ? "default" : "outline"}
onClick={() => setSelectedTime(time)}
className="w-full shadow-none"
>
{time}
</Button>
))}
</div>
</div>
</CardContent>
<CardFooter className="flex flex-col gap-4 border-t px-6 !py-5 md:flex-row">
<div className="text-sm">
{date && selectedTime ? (
<>
Your meeting is booked for{" "}
<span className="font-medium">
{" "}
{`${date.toDate("UTC").toLocaleDateString("en-US", {
weekday: "long",
day: "numeric",
month: "long",
})}`}{" "}
</span>
at <span className="font-medium">{selectedTime}</span>.
</>
) : (
<>Select a date and time for your meeting.</>
)}
</div>
<Button
disabled={!date || !selectedTime}
className="w-full md:ml-auto md:w-auto"
variant="outline"
>
Continue
</Button>
</CardFooter>
</Card>
)
}
With time presets
calendar-20
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
Your meeting is booked for Thursday, June 12 at 10:00.
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardFooter } from "@/components/ui/card"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar20() {
const [date, setDate] = React.useState<CalendarDate | undefined>(() =>
parseDate("2025-06-12")
)
const [selectedTime, setSelectedTime] = React.useState<string | null>("10:00")
const timeSlots = Array.from({ length: 37 }, (_, i) => {
const totalMinutes = i * 15
const hour = Math.floor(totalMinutes / 60) + 9
const minute = totalMinutes % 60
return `${hour.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}`
})
const bookedDates = new Set(
Array.from({ length: 3 }, (_, i) =>
parseDate(`2025-06-${(17 + i).toString().padStart(2, "0")}`)
)
)
const isBooked = (d: CalendarDate) =>
bookedDates.has(
parseDate(
`${d.year}-${String(d.month).padStart(2, "0")}-${String(d.day).padStart(2, "0")}`
)
)
return (
<Card className="gap-0 p-0">
<CardContent className="relative p-0 md:pr-48">
<div className="p-6">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={setDate}
isDateUnavailable={isBooked}
className="[--cell-size:--spacing(10)] md:[--cell-size:--spacing(12)]"
/>
</div>
</div>
<div className="no-scrollbar inset-y-0 right-0 flex max-h-72 w-full scroll-pb-6 flex-col gap-4 overflow-y-auto border-t p-6 md:absolute md:max-h-none md:w-48 md:border-t-0 md:border-l">
<div className="grid gap-2">
{timeSlots.map((time) => (
<Button
key={time}
variant={selectedTime === time ? "default" : "outline"}
onClick={() => setSelectedTime(time)}
className="w-full shadow-none"
>
{time}
</Button>
))}
</div>
</div>
</CardContent>
<CardFooter className="flex flex-col gap-4 border-t px-6 !py-5 md:flex-row">
<div className="text-sm">
{date && selectedTime ? (
<>
Your meeting is booked for{" "}
<span className="font-medium">
{" "}
{`${date.toDate("UTC").toLocaleDateString("en-US", {
weekday: "long",
day: "numeric",
month: "long",
})}`}{" "}
</span>
at <span className="font-medium">{selectedTime}</span>.
</>
) : (
<>Select a date and time for your meeting.</>
)}
</div>
<Button
disabled={!date || !selectedTime}
className="w-full md:ml-auto md:w-auto"
variant="outline"
>
Continue
</Button>
</CardFooter>
</Card>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import type { RangeValue } from "react-aria-components"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar21() {
const [range, setRange] = React.useState<RangeValue<CalendarDate>>(() => ({
start: parseDate("2025-06-12"),
end: parseDate("2025-06-17"),
}))
return (
<div className="inline-block rounded-lg border shadow-sm">
{/* Custom day content (price labels) is not supported in Preskok UI calendar */}
<RangeCalendar value={range} onChange={setRange} />
</div>
)
}
Custom days and formatters
calendar-21
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import type { RangeValue } from "react-aria-components"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar21() {
const [range, setRange] = React.useState<RangeValue<CalendarDate>>(() => ({
start: parseDate("2025-06-12"),
end: parseDate("2025-06-17"),
}))
return (
<div className="inline-block rounded-lg border shadow-sm">
{/* Custom day content (price labels) is not supported in Preskok UI calendar */}
<RangeCalendar value={range} onChange={setRange} />
</div>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { ChevronDownIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar22() {
const [open, setOpen] = React.useState(false)
const [date, setDate] = React.useState<CalendarDate | undefined>(undefined)
return (
<div className="flex flex-col gap-3">
<Label htmlFor="date" className="px-1">
Date of birth
</Label>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
id="date"
className="w-48 justify-between font-normal"
>
{date ? date.toDate("UTC").toLocaleDateString() : "Select date"}
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto overflow-hidden p-0" align="start">
<div className="inline-block rounded-lg border shadow-sm">
{/* Dropdown caption layout is not applicable; header includes dropdowns by default */}
<Calendar
value={date}
onChange={(value) => {
setDate(value)
setOpen(false)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
)
}
Date picker
calendar-22
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { ChevronDownIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar22() {
const [open, setOpen] = React.useState(false)
const [date, setDate] = React.useState<CalendarDate | undefined>(undefined)
return (
<div className="flex flex-col gap-3">
<Label htmlFor="date" className="px-1">
Date of birth
</Label>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
id="date"
className="w-48 justify-between font-normal"
>
{date ? date.toDate("UTC").toLocaleDateString() : "Select date"}
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto overflow-hidden p-0" align="start">
<div className="inline-block rounded-lg border shadow-sm">
{/* Dropdown caption layout is not applicable; header includes dropdowns by default */}
<Calendar
value={date}
onChange={(value) => {
setDate(value)
setOpen(false)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
)
}
Files
"use client"
import * as React from "react"
import { type CalendarDate } from "@internationalized/date"
import { ChevronDownIcon } from "lucide-react"
import type { RangeValue } from "react-aria-components"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar23() {
const [range, setRange] = React.useState<
RangeValue<CalendarDate> | undefined
>(undefined)
return (
<div className="flex flex-col gap-3">
<Label htmlFor="dates" className="px-1">
Select your stay
</Label>
<Popover>
<PopoverTrigger asChild>
<Button
variant="outline"
id="dates"
className="w-56 justify-between font-normal"
>
{range?.start && range?.end
? `${range.start.toDate("UTC").toLocaleDateString()} - ${range.end.toDate("UTC").toLocaleDateString()}`
: "Select date"}
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto overflow-hidden p-0" align="start">
<div className="inline-block rounded-lg border shadow-sm">
{/* Dropdown caption layout is not applicable; header includes dropdowns by default */}
<RangeCalendar
value={range}
onChange={(value) => {
setRange(value)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
)
}
Date range picker
calendar-23
"use client"
import * as React from "react"
import { type CalendarDate } from "@internationalized/date"
import { ChevronDownIcon } from "lucide-react"
import type { RangeValue } from "react-aria-components"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar23() {
const [range, setRange] = React.useState<
RangeValue<CalendarDate> | undefined
>(undefined)
return (
<div className="flex flex-col gap-3">
<Label htmlFor="dates" className="px-1">
Select your stay
</Label>
<Popover>
<PopoverTrigger asChild>
<Button
variant="outline"
id="dates"
className="w-56 justify-between font-normal"
>
{range?.start && range?.end
? `${range.start.toDate("UTC").toLocaleDateString()} - ${range.end.toDate("UTC").toLocaleDateString()}`
: "Select date"}
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto overflow-hidden p-0" align="start">
<div className="inline-block rounded-lg border shadow-sm">
{/* Dropdown caption layout is not applicable; header includes dropdowns by default */}
<RangeCalendar
value={range}
onChange={(value) => {
setRange(value)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
)
}
Files
"use client"
import * as React from "react"
import { type CalendarDate } from "@internationalized/date"
import { ChevronDownIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar24() {
const [open, setOpen] = React.useState(false)
const [date, setDate] = React.useState<CalendarDate | undefined>(undefined)
return (
<div className="flex gap-4">
<div className="flex flex-col gap-3">
<Label htmlFor="date-picker" className="px-1">
Date
</Label>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
id="date-picker"
className="w-32 justify-between font-normal"
>
{date ? date.toLocaleDateString() : "Select date"}
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto overflow-hidden p-0" align="start">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={(value) => {
setDate(value)
setOpen(false)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="time-picker" className="px-1">
Time
</Label>
<Input
type="time"
id="time-picker"
step="1"
defaultValue="10:30:00"
className="bg-background appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
</div>
)
}
Date and Time picker
calendar-24
"use client"
import * as React from "react"
import { type CalendarDate } from "@internationalized/date"
import { ChevronDownIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar24() {
const [open, setOpen] = React.useState(false)
const [date, setDate] = React.useState<CalendarDate | undefined>(undefined)
return (
<div className="flex gap-4">
<div className="flex flex-col gap-3">
<Label htmlFor="date-picker" className="px-1">
Date
</Label>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
id="date-picker"
className="w-32 justify-between font-normal"
>
{date ? date.toLocaleDateString() : "Select date"}
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto overflow-hidden p-0" align="start">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={(value) => {
setDate(value)
setOpen(false)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="time-picker" className="px-1">
Time
</Label>
<Input
type="time"
id="time-picker"
step="1"
defaultValue="10:30:00"
className="bg-background appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
</div>
)
}
Files
"use client"
import * as React from "react"
import { type CalendarDate } from "@internationalized/date"
import { ChevronDownIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar25() {
const [open, setOpen] = React.useState(false)
const [date, setDate] = React.useState<CalendarDate | undefined>(undefined)
return (
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-3">
<Label htmlFor="date" className="px-1">
Date
</Label>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
id="date"
className="w-full justify-between font-normal"
>
{date ? date.toLocaleDateString() : "Select date"}
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto overflow-hidden p-0" align="start">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={(value) => {
setDate(value)
setOpen(false)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
<div className="flex gap-4">
<div className="flex flex-col gap-3">
<Label htmlFor="time-from" className="px-1">
From
</Label>
<Input
type="time"
id="time-from"
step="1"
defaultValue="10:30:00"
className="bg-background appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="time-to" className="px-1">
To
</Label>
<Input
type="time"
id="time-to"
step="1"
defaultValue="12:30:00"
className="bg-background appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
</div>
</div>
)
}
Date and Time range picker
calendar-25
"use client"
import * as React from "react"
import { type CalendarDate } from "@internationalized/date"
import { ChevronDownIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar25() {
const [open, setOpen] = React.useState(false)
const [date, setDate] = React.useState<CalendarDate | undefined>(undefined)
return (
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-3">
<Label htmlFor="date" className="px-1">
Date
</Label>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
id="date"
className="w-full justify-between font-normal"
>
{date ? date.toLocaleDateString() : "Select date"}
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto overflow-hidden p-0" align="start">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={(value) => {
setDate(value)
setOpen(false)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
<div className="flex gap-4">
<div className="flex flex-col gap-3">
<Label htmlFor="time-from" className="px-1">
From
</Label>
<Input
type="time"
id="time-from"
step="1"
defaultValue="10:30:00"
className="bg-background appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="time-to" className="px-1">
To
</Label>
<Input
type="time"
id="time-to"
step="1"
defaultValue="12:30:00"
className="bg-background appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
</div>
</div>
)
}
Files
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { ChevronDownIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar26() {
const [openFrom, setOpenFrom] = React.useState(false)
const [openTo, setOpenTo] = React.useState(false)
const [dateFrom, setDateFrom] = React.useState<CalendarDate | undefined>(
parseDate("2025-06-01")
)
const [dateTo, setDateTo] = React.useState<CalendarDate | undefined>(
parseDate("2025-06-03")
)
return (
<div className="flex w-full max-w-64 min-w-0 flex-col gap-6">
<div className="flex gap-4">
<div className="flex flex-1 flex-col gap-3">
<Label htmlFor="date-from" className="px-1">
Check-in
</Label>
<Popover open={openFrom} onOpenChange={setOpenFrom}>
<PopoverTrigger asChild>
<Button
variant="outline"
id="date-from"
className="w-full justify-between font-normal"
>
{dateFrom
? dateFrom.toDate("UTC").toLocaleDateString("en-US", {
day: "2-digit",
month: "short",
year: "numeric",
})
: "Select date"}
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent
className="w-auto overflow-hidden p-0"
align="start"
>
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={dateFrom}
onChange={(value) => {
setDateFrom(value)
setOpenFrom(false)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="time-from" className="invisible px-1">
From
</Label>
<Input
type="time"
id="time-from"
step="1"
defaultValue="10:30:00"
className="bg-background appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
</div>
<div className="flex gap-4">
<div className="flex flex-1 flex-col gap-3">
<Label htmlFor="date-to" className="px-1">
Check-out
</Label>
<Popover open={openTo} onOpenChange={setOpenTo}>
<PopoverTrigger asChild>
<Button
variant="outline"
id="date-to"
className="w-full justify-between font-normal"
>
{dateTo
? dateTo.toDate("UTC").toLocaleDateString("en-US", {
day: "2-digit",
month: "short",
year: "numeric",
})
: "Select date"}
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent
className="w-auto overflow-hidden p-0"
align="start"
>
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={dateTo}
onChange={(value) => {
setDateTo(value)
setOpenTo(false)
}}
minValue={dateFrom}
/>
</div>
</PopoverContent>
</Popover>
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="time-to" className="invisible px-1">
To
</Label>
<Input
type="time"
id="time-to"
step="1"
defaultValue="12:30:00"
className="bg-background appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
</div>
</div>
)
}
Date range picker with time
calendar-26
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { ChevronDownIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
export function Calendar26() {
const [openFrom, setOpenFrom] = React.useState(false)
const [openTo, setOpenTo] = React.useState(false)
const [dateFrom, setDateFrom] = React.useState<CalendarDate | undefined>(
parseDate("2025-06-01")
)
const [dateTo, setDateTo] = React.useState<CalendarDate | undefined>(
parseDate("2025-06-03")
)
return (
<div className="flex w-full max-w-64 min-w-0 flex-col gap-6">
<div className="flex gap-4">
<div className="flex flex-1 flex-col gap-3">
<Label htmlFor="date-from" className="px-1">
Check-in
</Label>
<Popover open={openFrom} onOpenChange={setOpenFrom}>
<PopoverTrigger asChild>
<Button
variant="outline"
id="date-from"
className="w-full justify-between font-normal"
>
{dateFrom
? dateFrom.toDate("UTC").toLocaleDateString("en-US", {
day: "2-digit",
month: "short",
year: "numeric",
})
: "Select date"}
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent
className="w-auto overflow-hidden p-0"
align="start"
>
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={dateFrom}
onChange={(value) => {
setDateFrom(value)
setOpenFrom(false)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="time-from" className="invisible px-1">
From
</Label>
<Input
type="time"
id="time-from"
step="1"
defaultValue="10:30:00"
className="bg-background appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
</div>
<div className="flex gap-4">
<div className="flex flex-1 flex-col gap-3">
<Label htmlFor="date-to" className="px-1">
Check-out
</Label>
<Popover open={openTo} onOpenChange={setOpenTo}>
<PopoverTrigger asChild>
<Button
variant="outline"
id="date-to"
className="w-full justify-between font-normal"
>
{dateTo
? dateTo.toDate("UTC").toLocaleDateString("en-US", {
day: "2-digit",
month: "short",
year: "numeric",
})
: "Select date"}
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent
className="w-auto overflow-hidden p-0"
align="start"
>
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={dateTo}
onChange={(value) => {
setDateTo(value)
setOpenTo(false)
}}
minValue={dateFrom}
/>
</div>
</PopoverContent>
</Popover>
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="time-to" className="invisible px-1">
To
</Label>
<Input
type="time"
id="time-to"
step="1"
defaultValue="12:30:00"
className="bg-background appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
/>
</div>
</div>
</div>
)
}
Files
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { CalendarIcon } from "lucide-react"
import type { RangeValue } from "react-aria-components"
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts"
import { Button } from "@/components/ui/button"
import {
Card,
CardAction,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import {
ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/preskok-ui/chart-helpers"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
const chartData = [
{ date: "2025-06-01", visitors: 178 },
{ date: "2025-06-02", visitors: 470 },
{ date: "2025-06-03", visitors: 103 },
{ date: "2025-06-04", visitors: 439 },
{ date: "2025-06-05", visitors: 88 },
{ date: "2025-06-06", visitors: 294 },
{ date: "2025-06-07", visitors: 323 },
{ date: "2025-06-08", visitors: 385 },
{ date: "2025-06-09", visitors: 438 },
{ date: "2025-06-10", visitors: 155 },
{ date: "2025-06-11", visitors: 92 },
{ date: "2025-06-12", visitors: 492 },
{ date: "2025-06-13", visitors: 81 },
{ date: "2025-06-14", visitors: 426 },
{ date: "2025-06-15", visitors: 307 },
{ date: "2025-06-16", visitors: 371 },
{ date: "2025-06-17", visitors: 475 },
{ date: "2025-06-18", visitors: 107 },
{ date: "2025-06-19", visitors: 341 },
{ date: "2025-06-20", visitors: 408 },
{ date: "2025-06-21", visitors: 169 },
{ date: "2025-06-22", visitors: 317 },
{ date: "2025-06-23", visitors: 480 },
{ date: "2025-06-24", visitors: 132 },
{ date: "2025-06-25", visitors: 141 },
{ date: "2025-06-26", visitors: 434 },
{ date: "2025-06-27", visitors: 448 },
{ date: "2025-06-28", visitors: 149 },
{ date: "2025-06-29", visitors: 103 },
{ date: "2025-06-30", visitors: 446 },
]
const total = chartData.reduce((acc, curr) => acc + curr.visitors, 0)
const chartConfig = {
visitors: {
label: "Visitors",
color: "var(--color-primary)",
},
} satisfies ChartConfig
export function Calendar27() {
const [range, setRange] = React.useState<RangeValue<CalendarDate>>({
start: parseDate("2025-06-05"),
end: parseDate("2025-06-20"),
})
const filteredData = React.useMemo(() => {
if (!range?.start && !range?.end) {
return chartData
}
return chartData.filter((item) => {
const date = new Date(item.date)
const start = range.start?.toDate("UTC")
const end = range.end?.toDate("UTC")
return (!start || date >= start) && (!end || date <= end)
})
}, [range])
return (
<Card className="@container/card w-full max-w-xl">
<CardHeader className="flex flex-col border-b @md/card:grid">
<CardTitle>Web Analytics</CardTitle>
<CardDescription>
Showing total visitors for this month.
</CardDescription>
<CardAction className="mt-2 @md/card:mt-0">
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">
<CalendarIcon />
{range?.start && range?.end
? `${range.start.toDate("UTC").toLocaleDateString()} - ${range.end.toDate("UTC").toLocaleDateString()}`
: "June 2025"}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto overflow-hidden p-0" align="end">
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={range}
onChange={setRange}
minValue={parseDate("2025-06-01")}
maxValue={parseDate("2025-06-30")}
/>
</div>
</PopoverContent>
</Popover>
</CardAction>
</CardHeader>
<CardContent className="px-4">
<ChartContainer
config={chartConfig}
className="aspect-auto h-[250px] w-full"
>
<BarChart
accessibilityLayer
data={filteredData}
margin={{
left: 12,
right: 12,
}}
>
<CartesianGrid vertical={false} />
<XAxis
dataKey="date"
tickLine={false}
axisLine={false}
tickMargin={8}
minTickGap={20}
tickFormatter={(value) => {
const date = new Date(value)
return date.toLocaleDateString("en-US", {
day: "numeric",
})
}}
/>
<ChartTooltip
content={
<ChartTooltipContent
className="w-[150px]"
nameKey="visitors"
labelFormatter={(value) => {
return new Date(value).toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
})
}}
/>
}
/>
<Bar dataKey="visitors" fill={`var(--color-visitors)`} radius={4} />
</BarChart>
</ChartContainer>
</CardContent>
<CardFooter className="border-t">
<div className="text-sm">
You had{" "}
<span className="font-semibold">{total.toLocaleString()}</span>{" "}
visitors for the month of June.
</div>
</CardFooter>
</Card>
)
}
Chart filter
calendar-27
Web Analytics
Showing total visitors for this month.
You had 8,792 visitors for the month of June.
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { CalendarIcon } from "lucide-react"
import type { RangeValue } from "react-aria-components"
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts"
import { Button } from "@/components/ui/button"
import {
Card,
CardAction,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import {
ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/preskok-ui/chart-helpers"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
const chartData = [
{ date: "2025-06-01", visitors: 178 },
{ date: "2025-06-02", visitors: 470 },
{ date: "2025-06-03", visitors: 103 },
{ date: "2025-06-04", visitors: 439 },
{ date: "2025-06-05", visitors: 88 },
{ date: "2025-06-06", visitors: 294 },
{ date: "2025-06-07", visitors: 323 },
{ date: "2025-06-08", visitors: 385 },
{ date: "2025-06-09", visitors: 438 },
{ date: "2025-06-10", visitors: 155 },
{ date: "2025-06-11", visitors: 92 },
{ date: "2025-06-12", visitors: 492 },
{ date: "2025-06-13", visitors: 81 },
{ date: "2025-06-14", visitors: 426 },
{ date: "2025-06-15", visitors: 307 },
{ date: "2025-06-16", visitors: 371 },
{ date: "2025-06-17", visitors: 475 },
{ date: "2025-06-18", visitors: 107 },
{ date: "2025-06-19", visitors: 341 },
{ date: "2025-06-20", visitors: 408 },
{ date: "2025-06-21", visitors: 169 },
{ date: "2025-06-22", visitors: 317 },
{ date: "2025-06-23", visitors: 480 },
{ date: "2025-06-24", visitors: 132 },
{ date: "2025-06-25", visitors: 141 },
{ date: "2025-06-26", visitors: 434 },
{ date: "2025-06-27", visitors: 448 },
{ date: "2025-06-28", visitors: 149 },
{ date: "2025-06-29", visitors: 103 },
{ date: "2025-06-30", visitors: 446 },
]
const total = chartData.reduce((acc, curr) => acc + curr.visitors, 0)
const chartConfig = {
visitors: {
label: "Visitors",
color: "var(--color-primary)",
},
} satisfies ChartConfig
export function Calendar27() {
const [range, setRange] = React.useState<RangeValue<CalendarDate>>({
start: parseDate("2025-06-05"),
end: parseDate("2025-06-20"),
})
const filteredData = React.useMemo(() => {
if (!range?.start && !range?.end) {
return chartData
}
return chartData.filter((item) => {
const date = new Date(item.date)
const start = range.start?.toDate("UTC")
const end = range.end?.toDate("UTC")
return (!start || date >= start) && (!end || date <= end)
})
}, [range])
return (
<Card className="@container/card w-full max-w-xl">
<CardHeader className="flex flex-col border-b @md/card:grid">
<CardTitle>Web Analytics</CardTitle>
<CardDescription>
Showing total visitors for this month.
</CardDescription>
<CardAction className="mt-2 @md/card:mt-0">
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">
<CalendarIcon />
{range?.start && range?.end
? `${range.start.toDate("UTC").toLocaleDateString()} - ${range.end.toDate("UTC").toLocaleDateString()}`
: "June 2025"}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto overflow-hidden p-0" align="end">
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={range}
onChange={setRange}
minValue={parseDate("2025-06-01")}
maxValue={parseDate("2025-06-30")}
/>
</div>
</PopoverContent>
</Popover>
</CardAction>
</CardHeader>
<CardContent className="px-4">
<ChartContainer
config={chartConfig}
className="aspect-auto h-[250px] w-full"
>
<BarChart
accessibilityLayer
data={filteredData}
margin={{
left: 12,
right: 12,
}}
>
<CartesianGrid vertical={false} />
<XAxis
dataKey="date"
tickLine={false}
axisLine={false}
tickMargin={8}
minTickGap={20}
tickFormatter={(value) => {
const date = new Date(value)
return date.toLocaleDateString("en-US", {
day: "numeric",
})
}}
/>
<ChartTooltip
content={
<ChartTooltipContent
className="w-[150px]"
nameKey="visitors"
labelFormatter={(value) => {
return new Date(value).toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
})
}}
/>
}
/>
<Bar dataKey="visitors" fill={`var(--color-visitors)`} radius={4} />
</BarChart>
</ChartContainer>
</CardContent>
<CardFooter className="border-t">
<div className="text-sm">
You had{" "}
<span className="font-semibold">{total.toLocaleString()}</span>{" "}
visitors for the month of June.
</div>
</CardFooter>
</Card>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { CalendarIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
function formatDate(date: CalendarDate | undefined) {
if (!date) {
return ""
}
return date.toDate("UTC").toLocaleDateString("en-US", {
day: "2-digit",
month: "long",
year: "numeric",
})
}
function isValidDate(date: Date | undefined) {
if (!date) {
return false
}
return !isNaN(date.getTime())
}
export function Calendar28() {
const [open, setOpen] = React.useState(false)
const [date, setDate] = React.useState<CalendarDate | undefined>(
parseDate("2025-06-01")
)
const [value, setValue] = React.useState(formatDate(date))
return (
<div className="flex flex-col gap-3">
<Label htmlFor="date" className="px-1">
Subscription Date
</Label>
<div className="relative flex gap-2">
<Input
id="date"
value={value}
placeholder="June 01, 2025"
className="bg-background pr-10"
onChange={(e) => {
const date = new Date(e.target.value)
setValue(e.target.value)
if (isValidDate(date)) {
setDate(
parseDate(
`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`
)
)
}
}}
onKeyDown={(e) => {
if (e.key === "ArrowDown") {
e.preventDefault()
setOpen(true)
}
}}
/>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
id="date-picker"
variant="ghost"
className="absolute top-1/2 right-2 size-6 -translate-y-1/2"
>
<CalendarIcon className="size-3.5" />
<span className="sr-only">Select date</span>
</Button>
</PopoverTrigger>
<PopoverContent
className="w-auto overflow-hidden p-0"
align="end"
alignOffset={-8}
sideOffset={10}
>
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={(value) => {
setDate(value)
setValue(formatDate(value))
setOpen(false)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
</div>
)
}
Input with date picker
calendar-28
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { CalendarIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
function formatDate(date: CalendarDate | undefined) {
if (!date) {
return ""
}
return date.toDate("UTC").toLocaleDateString("en-US", {
day: "2-digit",
month: "long",
year: "numeric",
})
}
function isValidDate(date: Date | undefined) {
if (!date) {
return false
}
return !isNaN(date.getTime())
}
export function Calendar28() {
const [open, setOpen] = React.useState(false)
const [date, setDate] = React.useState<CalendarDate | undefined>(
parseDate("2025-06-01")
)
const [value, setValue] = React.useState(formatDate(date))
return (
<div className="flex flex-col gap-3">
<Label htmlFor="date" className="px-1">
Subscription Date
</Label>
<div className="relative flex gap-2">
<Input
id="date"
value={value}
placeholder="June 01, 2025"
className="bg-background pr-10"
onChange={(e) => {
const date = new Date(e.target.value)
setValue(e.target.value)
if (isValidDate(date)) {
setDate(
parseDate(
`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`
)
)
}
}}
onKeyDown={(e) => {
if (e.key === "ArrowDown") {
e.preventDefault()
setOpen(true)
}
}}
/>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
id="date-picker"
variant="ghost"
className="absolute top-1/2 right-2 size-6 -translate-y-1/2"
>
<CalendarIcon className="size-3.5" />
<span className="sr-only">Select date</span>
</Button>
</PopoverTrigger>
<PopoverContent
className="w-auto overflow-hidden p-0"
align="end"
alignOffset={-8}
sideOffset={10}
>
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={(value) => {
setDate(value)
setValue(formatDate(value))
setOpen(false)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
</div>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { parseDate as parseNatural } from "chrono-node"
import { CalendarIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
function formatDate(date: CalendarDate | undefined) {
if (!date) {
return ""
}
return date.toDate("UTC").toLocaleDateString("en-US", {
day: "2-digit",
month: "long",
year: "numeric",
})
}
export function Calendar29() {
const [open, setOpen] = React.useState(false)
const [value, setValue] = React.useState("In 2 days")
const initial = parseNatural(value)
const [date, setDate] = React.useState<CalendarDate | undefined>(
initial
? parseDate(
`${initial.getFullYear()}-${String(initial.getMonth() + 1).padStart(2, "0")}-${String(initial.getDate()).padStart(2, "0")}`
)
: undefined
)
return (
<div className="flex flex-col gap-3">
<Label htmlFor="date" className="px-1">
Schedule Date
</Label>
<div className="relative flex gap-2">
<Input
id="date"
value={value}
placeholder="Tomorrow or next week"
className="bg-background pr-10"
onChange={(e) => {
setValue(e.target.value)
const d = parseNatural(e.target.value)
if (d) {
setDate(
parseDate(
`${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`
)
)
}
}}
onKeyDown={(e) => {
if (e.key === "ArrowDown") {
e.preventDefault()
setOpen(true)
}
}}
/>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
id="date-picker"
variant="ghost"
className="absolute top-1/2 right-2 size-6 -translate-y-1/2"
>
<CalendarIcon className="size-3.5" />
<span className="sr-only">Select date</span>
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto overflow-hidden p-0" align="end">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={(value) => {
setDate(value)
setValue(formatDate(value))
setOpen(false)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
<div className="text-muted-foreground px-1 text-sm">
Your post will be published on{" "}
<span className="font-medium">{formatDate(date)}</span>.
</div>
</div>
)
}
Natural language date picker
calendar-29
Your post will be published on August 30, 2025.
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { parseDate as parseNatural } from "chrono-node"
import { CalendarIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
function formatDate(date: CalendarDate | undefined) {
if (!date) {
return ""
}
return date.toDate("UTC").toLocaleDateString("en-US", {
day: "2-digit",
month: "long",
year: "numeric",
})
}
export function Calendar29() {
const [open, setOpen] = React.useState(false)
const [value, setValue] = React.useState("In 2 days")
const initial = parseNatural(value)
const [date, setDate] = React.useState<CalendarDate | undefined>(
initial
? parseDate(
`${initial.getFullYear()}-${String(initial.getMonth() + 1).padStart(2, "0")}-${String(initial.getDate()).padStart(2, "0")}`
)
: undefined
)
return (
<div className="flex flex-col gap-3">
<Label htmlFor="date" className="px-1">
Schedule Date
</Label>
<div className="relative flex gap-2">
<Input
id="date"
value={value}
placeholder="Tomorrow or next week"
className="bg-background pr-10"
onChange={(e) => {
setValue(e.target.value)
const d = parseNatural(e.target.value)
if (d) {
setDate(
parseDate(
`${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`
)
)
}
}}
onKeyDown={(e) => {
if (e.key === "ArrowDown") {
e.preventDefault()
setOpen(true)
}
}}
/>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
id="date-picker"
variant="ghost"
className="absolute top-1/2 right-2 size-6 -translate-y-1/2"
>
<CalendarIcon className="size-3.5" />
<span className="sr-only">Select date</span>
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto overflow-hidden p-0" align="end">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar
value={date}
onChange={(value) => {
setDate(value)
setValue(formatDate(value))
setOpen(false)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
<div className="text-muted-foreground px-1 text-sm">
Your post will be published on{" "}
<span className="font-medium">{formatDate(date)}</span>.
</div>
</div>
)
}
Files
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { formatDateRange } from "little-date"
import { ChevronDownIcon } from "lucide-react"
import type { RangeValue } from "react-aria-components"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar30() {
const [range, setRange] = React.useState<RangeValue<CalendarDate>>({
start: parseDate("2025-06-04"),
end: parseDate("2025-06-10"),
})
return (
<div className="flex flex-col gap-3">
<Label htmlFor="dates" className="px-1">
Select your stay
</Label>
<Popover>
<PopoverTrigger asChild>
<Button
variant="outline"
id="dates"
className="w-56 justify-between font-normal"
>
{range?.start && range?.end
? formatDateRange(
range.start.toDate("UTC"),
range.end.toDate("UTC"),
{
includeTime: false,
}
)
: "Select date"}
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto overflow-hidden p-0" align="start">
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={range}
onChange={(value) => {
setRange(value)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
)
}
With little-date
calendar-30
"use client"
import * as React from "react"
import { parseDate, type CalendarDate } from "@internationalized/date"
import { formatDateRange } from "little-date"
import { ChevronDownIcon } from "lucide-react"
import type { RangeValue } from "react-aria-components"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { RangeCalendar } from "@/components/ui/preskok-ui/range-calendar"
export function Calendar30() {
const [range, setRange] = React.useState<RangeValue<CalendarDate>>({
start: parseDate("2025-06-04"),
end: parseDate("2025-06-10"),
})
return (
<div className="flex flex-col gap-3">
<Label htmlFor="dates" className="px-1">
Select your stay
</Label>
<Popover>
<PopoverTrigger asChild>
<Button
variant="outline"
id="dates"
className="w-56 justify-between font-normal"
>
{range?.start && range?.end
? formatDateRange(
range.start.toDate("UTC"),
range.end.toDate("UTC"),
{
includeTime: false,
}
)
: "Select date"}
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto overflow-hidden p-0" align="start">
<div className="inline-block rounded-lg border shadow-sm">
<RangeCalendar
value={range}
onChange={(value) => {
setRange(value)
}}
/>
</div>
</PopoverContent>
</Popover>
</div>
)
}
Files
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { formatDateRange } from "little-date"
import { PlusIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardFooter } from "@/components/ui/card"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
const events = [
{
title: "Team Sync Meeting",
from: "2025-06-12T09:00:00",
to: "2025-06-12T10:00:00",
},
{
title: "Design Review",
from: "2025-06-12T11:30:00",
to: "2025-06-12T12:30:00",
},
{
title: "Client Presentation",
from: "2025-06-12T14:00:00",
to: "2025-06-12T15:00:00",
},
]
export function Calendar31() {
const [date, setDate] = React.useState<CalendarDate | undefined>(
parseDate("2025-06-12")
)
return (
<Card className="w-fit py-4">
<CardContent className="px-4">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} />
</div>
</CardContent>
<CardFooter className="flex flex-col items-start gap-3 border-t px-4 !pt-4">
<div className="flex w-full items-center justify-between px-1">
<div className="text-sm font-medium">
{date?.toDate("UTC").toLocaleDateString("en-US", {
day: "numeric",
month: "long",
year: "numeric",
})}
</div>
<Button
variant="ghost"
size="icon"
className="size-6"
title="Add Event"
>
<PlusIcon />
<span className="sr-only">Add Event</span>
</Button>
</div>
<div className="flex w-full flex-col gap-2">
{events.map((event) => (
<div
key={event.title}
className="bg-muted after:bg-primary/70 relative rounded-md p-2 pl-6 text-sm after:absolute after:inset-y-2 after:left-2 after:w-1 after:rounded-full"
>
<div className="font-medium">{event.title}</div>
<div className="text-muted-foreground text-xs">
{formatDateRange(new Date(event.from), new Date(event.to))}
</div>
</div>
))}
</div>
</CardFooter>
</Card>
)
}
With event slots
calendar-31
June 2025
June 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 | 1 | 2 | 3 | 4 | 5 |
June 12, 2025
Team Sync Meeting
Jun 12, 9am - 10am
Design Review
Jun 12, 11:30am - 12:30pm
Client Presentation
Jun 12, 2pm - 3pm
"use client"
import * as React from "react"
import type { CalendarDate } from "@internationalized/date"
import { parseDate } from "@internationalized/date"
import { formatDateRange } from "little-date"
import { PlusIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardFooter } from "@/components/ui/card"
import { Calendar } from "@/components/ui/preskok-ui/calendar"
const events = [
{
title: "Team Sync Meeting",
from: "2025-06-12T09:00:00",
to: "2025-06-12T10:00:00",
},
{
title: "Design Review",
from: "2025-06-12T11:30:00",
to: "2025-06-12T12:30:00",
},
{
title: "Client Presentation",
from: "2025-06-12T14:00:00",
to: "2025-06-12T15:00:00",
},
]
export function Calendar31() {
const [date, setDate] = React.useState<CalendarDate | undefined>(
parseDate("2025-06-12")
)
return (
<Card className="w-fit py-4">
<CardContent className="px-4">
<div className="inline-block rounded-lg border shadow-sm">
<Calendar value={date} onChange={setDate} />
</div>
</CardContent>
<CardFooter className="flex flex-col items-start gap-3 border-t px-4 !pt-4">
<div className="flex w-full items-center justify-between px-1">
<div className="text-sm font-medium">
{date?.toDate("UTC").toLocaleDateString("en-US", {
day: "numeric",
month: "long",
year: "numeric",
})}
</div>
<Button
variant="ghost"
size="icon"
className="size-6"
title="Add Event"
>
<PlusIcon />
<span className="sr-only">Add Event</span>
</Button>
</div>
<div className="flex w-full flex-col gap-2">
{events.map((event) => (
<div
key={event.title}
className="bg-muted after:bg-primary/70 relative rounded-md p-2 pl-6 text-sm after:absolute after:inset-y-2 after:left-2 after:w-1 after:rounded-full"
>
<div className="font-medium">{event.title}</div>
<div className="text-muted-foreground text-xs">
{formatDateRange(new Date(event.from), new Date(event.to))}
</div>
</div>
))}
</div>
</CardFooter>
</Card>
)
}