preskok/ui

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
components/calendar-01.tsx
"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
Files
components/calendar-02.tsx
"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
Files
components/calendar-03.tsx
"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
Files
components/calendar-04.tsx
"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
Files
components/calendar-05.tsx
"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
Files
components/calendar-06.tsx
"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
Files
components/calendar-07.tsx
"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
Files
components/calendar-08.tsx
"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
Files
components/calendar-09.tsx
"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
Files
components/calendar-10.tsx
"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
Files
components/calendar-11.tsx
"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
Files
components/calendar-12.tsx
"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
Files
components/calendar-13.tsx
"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
Files
components/calendar-14.tsx
"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
Files
components/calendar-15.tsx
"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
Files
components/calendar-16.tsx
"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
Files
components/calendar-17.tsx
"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
Files
components/calendar-18.tsx
"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
Files
components/calendar-19.tsx
"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
Files
components/calendar-20.tsx
"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
Files
components/calendar-21.tsx
"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
Files
components/calendar-22.tsx
"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
Files
components/calendar-23.tsx
"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
Files
components/calendar-24.tsx
"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
Files
components/calendar-25.tsx
"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
Files
components/calendar-26.tsx
"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
Files
components/calendar-27.tsx
"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
Files
components/calendar-28.tsx
"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
Files
components/calendar-29.tsx
"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
Files
components/calendar-30.tsx
"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
Files
components/calendar-31.tsx
"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