HextaUI

Calendar

Tekli, aralık ve çoklu seçim için, kayan aylar, aralık önizlemeleri ve dokunmaya uygun boyutta günler içeren bir tarih ızgarası.

October 2026
"use client"

import * as React from "react"
import { format } from "date-fns"

import { Calendar } from "@/components/ui/calendar"

export function CalendarDemo() {
  const [date, setDate] = React.useState<Date>()

  return (
    <div className="w-fit max-w-full overflow-x-auto rounded-xl border">
      <Calendar
        mode="single"
        selected={date}
        onSelect={setDate}
        footer={date ? `Selected ${format(date, "PPP")}.` : "Pick a day."}
      />
    </div>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/calendar.json

Bileşeni, HextaUI tema token'larını ve bileşenin bağımlı olduğu tüm HextaUI bileşenlerini ekler.

import { Calendar } from "@/components/ui/calendar"
const [date, setDate] = React.useState<Date>()

<Calendar mode="single" selected={date} onSelect={setDate} />

Calendar, react-day-picker'ın <DayPicker /> bileşenini sarar; bu yüzden her DayPicker prop'u daypicker.dev'de belgelendiği gibi çalışır. HextaUI stil, ay geçişleri, aralık önizlemesi ve hydration açısından güvenli bir bugün ekler.

Aralık

mode="range" ile, ilk tıklamadan sonra bir günün üzerine gelmek veya odaklanmak, sonraki tıklamanın seçeceği aralığı önizler. numberOfMonths ayları yan yana gösterir; dar ekranlarda üst üste dizilir.

"use client"

import * as React from "react"
import { format } from "date-fns"
import type { DateRange } from "react-day-picker"

import { Calendar } from "@/components/ui/calendar"

export function CalendarRange() {
  const [range, setRange] = React.useState<DateRange>()

  return (
    <div className="max-w-full overflow-x-auto rounded-xl border">
      <Calendar
        mode="range"
        numberOfMonths={2}
        selected={range}
        onSelect={setRange}
        footer={
          range?.from && range.to
            ? `${format(range.from, "PP")} – ${format(range.to, "PP")}`
            : range?.from
              ? "Pick an end date."
              : "Pick a start date."
        }
      />
    </div>
  )
}

Aralık sınırları

min ve max aralık uzunluğunu gün olarak sınırlar. excludeDisabled ile, devre dışı bir günü içerecek bir aralık yeniden başlar.

import { Calendar } from "@/components/ui/calendar"

export function CalendarRangeLimits() {
  return (
    <div className="w-fit max-w-full overflow-x-auto rounded-xl border">
      <Calendar
        mode="range"
        min={2}
        max={7}
        disabled={{ dayOfWeek: [0, 6] }}
        excludeDisabled
        footer="Weekdays only, 2–7 days."
      />
    </div>
  )
}

Çoklu

mode="multiple" tek tek günleri açıp kapatır. max kaç günün seçilebileceğini sınırlar.

import { Calendar } from "@/components/ui/calendar"

export function CalendarMultiple() {
  return (
    <div className="w-fit max-w-full overflow-x-auto rounded-xl border">
      <Calendar mode="multiple" max={5} footer="Pick up to five days." />
    </div>
  )
}

Ay ve yıl dropdown'ları

captionLayout="dropdown" başlığı yerel select'lerle değiştirir; böylece telefonlar kendi seçicisini alır. Yılları sınırlamak için startMonth ve endMonth ayarlayın.

import { Calendar } from "@/components/ui/calendar"

export function CalendarDropdowns() {
  return (
    <div className="w-fit max-w-full overflow-x-auto rounded-xl border">
      <Calendar
        mode="single"
        captionLayout="dropdown"
        startMonth={new Date(1940, 0)}
        endMonth={new Date(2035, 11)}
        defaultMonth={new Date(1995, 5)}
      />
    </div>
  )
}

Sınırlı

Gezinme startMonth ve endMonth değerlerinde durur, disabled ise pencere dışındaki günleri engeller. useToday() sunucu tarafı render sırasında güvenle kullanılabilecek bir bugün verir.

"use client"

import { addDays, startOfMonth } from "date-fns"

import { Calendar } from "@/components/ui/calendar"
import { useToday } from "@/hooks/use-today"

export function CalendarBounded() {
  const today = useToday()
  const last = today && addDays(today, 45)

  return (
    <div className="w-fit max-w-full overflow-x-auto rounded-xl border">
      <Calendar
        mode="single"
        startMonth={today && startOfMonth(today)}
        endMonth={last && startOfMonth(last)}
        disabled={
          today && last ? [{ before: today }, { after: last }] : undefined
        }
        footer="Bookable for the next 45 days."
      />
    </div>
  )
}

Kontrollü ay

Görünen ayı yönetmek için month ve onMonthChange geçin. Atlamalar gidiş yönünde kayar ve yükseklik 5 ile 6 haftalık satırlar arasında yumuşakça değişir.

"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import { useToday } from "@/hooks/use-today"

export function CalendarControlled() {
  const today = useToday()
  const [month, setMonth] = React.useState<Date>()
  const [date, setDate] = React.useState<Date>()
  const shown = month ?? today

  return (
    <div className="flex max-w-full min-w-0 flex-col items-center gap-3">
      <div className="w-fit max-w-full overflow-x-auto rounded-xl border">
        <Calendar
          mode="single"
          month={shown}
          onMonthChange={setMonth}
          selected={date}
          onSelect={setDate}
        />
      </div>
      <div className="flex gap-2">
        <Button
          variant="outline"
          size="sm"
          onClick={() => {
            const now = new Date()
            setMonth(now)
            setDate(now)
          }}
        >
          Today
        </Button>
        <Button
          variant="outline"
          size="sm"
          onClick={() => {
            const base = shown ?? new Date()
            setMonth(new Date(base.getFullYear() + 1, base.getMonth()))
          }}
        >
          Next year
        </Button>
      </div>
    </div>
  )
}

Hafta numaraları

showWeekNumber bir hafta sütunu ekler. ISOWeek Pazartesi ile başlayan ISO numaralandırmasını kullanır. showOutsideDays={false} diğer aylardaki günleri gizler.

import { Calendar } from "@/components/ui/calendar"

export function CalendarWeekNumbers() {
  return (
    <div className="w-fit max-w-full overflow-x-auto rounded-xl border">
      <Calendar mode="range" showWeekNumber ISOWeek showOutsideDays={false} />
    </div>
  )
}

Sabit bugün

Vurgulanan günü sabitlemek için, testler veya başka bir saat dilimi için today geçin. animate={false} ay geçişlerini kapatır.

"use client"

import * as React from "react"
import type { DateRange } from "react-day-picker"

import { Calendar } from "@/components/ui/calendar"

export function CalendarFixedToday() {
  const [range, setRange] = React.useState<DateRange | undefined>({
    from: new Date(2026, 1, 9),
    to: new Date(2026, 1, 17),
  })

  return (
    <div className="w-fit max-w-full overflow-x-auto rounded-xl border">
      <Calendar
        mode="range"
        today={new Date(2026, 1, 11)}
        defaultMonth={new Date(2026, 1)}
        selected={range}
        onSelect={setRange}
        animate={false}
      />
    </div>
  )
}

Sheet içinde

Bir sheet, popover veya diyalog içinde takvim kendi arka planını bırakır ve yüzeyle kaynaşır.

"use client"

import * as React from "react"
import { format } from "date-fns"

import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import {
  Sheet,
  SheetBody,
  SheetContent,
  SheetDescription,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@/components/ui/sheet"

export function CalendarSheet() {
  const [date, setDate] = React.useState<Date>()

  return (
    <Sheet>
      <SheetTrigger render={<Button variant="outline" />}>
        {date ? format(date, "PPP") : "Choose a date"}
      </SheetTrigger>
      <SheetContent>
        <SheetHeader>
          <SheetTitle>Schedule</SheetTitle>
          <SheetDescription>Pick a delivery day.</SheetDescription>
        </SheetHeader>
        <SheetBody>
          <Calendar mode="single" selected={date} onSelect={setDate} />
        </SheetBody>
      </SheetContent>
    </Sheet>
  )
}

Sağdan sola

react-day-picker/locale içinden bir locale ve dir="rtl" geçin. Oklar, gezinme ve kayma yönünün hepsi yansıtılır. dir="rtl" olan bir DirectionProvider içinde yön otomatik olarak alınır.

"use client"

import { arSA } from "react-day-picker/locale"

import { Calendar } from "@/components/ui/calendar"

export function CalendarRtl() {
  return (
    <div dir="rtl" className="max-w-full min-w-0">
      <div className="w-fit max-w-full overflow-x-auto rounded-xl border">
        <Calendar mode="range" locale={arSA} dir="rtl" />
      </div>
    </div>
  )
}

Bir güne odaklanın, sonra bu tuşları kullanın. Görünen ayı aşmak ayı değiştirir.

TuşAction
←→Önceki veya sonraki gün. Sağdan sola düzenlerde ters çevrilir.
↑↓Önceki veya sonraki haftanın aynı günü.
Shift←→Önceki veya sonraki ay.
Shift↑↓Önceki veya sonraki yıl.
Page UpPage DownÖnceki veya sonraki ay.
ShiftPage UpPage DownÖnceki veya sonraki yıl.
HomeHaftanın ilk günü.
EndHaftanın son günü.
EnterSpaceOdaktaki günü seçer.
  • Ay bir ızgaradır. Her gün tam tarih etiketli bir düğmedir ve seçili günler aria-selected ayarlar.
  • Klavyeyle yapılan ay değişiklikleri kaymayı atlar ve yalnızca solar; böylece odak, hareket eden bir ızgaranın altında asla kaymaz.
  • Azaltılmış harekette ay değişiklikleri solar ve yükseklik değişimi anlıktır.
  • Dokunmatik ekranlarda gün hücreleri 44px'e büyür.

Tüm <DayPicker /> prop'larını kabul eder. Aşağıdaki varsayılanlar DayPicker'dakilerden farklıdır veya HextaUI tarafından eklenmiştir.

PropTürVarsayılan
modeMod olmadan günler seçilemez.
"single" | "multiple" | "range"–
selectedMod ile eşleşir.
Date | Date[] | DateRange–
onSelect
(selected, triggerDate, modifiers, event) => void–
requiredSon seçimin kaldırılmasını engeller.
boolean–
minBir aralıktaki veya multiple modunda seçilecek en az gün.
number–
maxBir aralıktaki veya multiple modunda seçilebilecek en fazla gün.
number–
excludeDisabledAralık modu.
boolean–
disabled
Matcher | Matcher[]–
monthKontrollü ay.
Date–
defaultMonth
Date–
onMonthChange
(month: Date) => void–
startMonth
Date–
endMonth
Date–
numberOfMonths
number1
captionLayout
"label" | "dropdown" | "dropdown-months" | "dropdown-years""label"
navLayoutHextaUI varsayılanı. Oklar başlığın iki yanında durur.
"around" | "after""around"
showOutsideDaysHextaUI varsayılanı.
booleantrue
animateAy kayması ve yükseklik geçişleri. HextaUI varsayılanı.
booleantrue
buttonVariantÖnceki ve sonraki düğmelerin variant'ı.
Button variant"ghost"
showWeekNumber
booleanfalse
ISOWeek
booleanfalse
weekStartsOn
0 | 1 | 2 | 3 | 4 | 5 | 6–
fixedWeeks
booleanfalse
todayVarsayılan olarak istemcinin bugünüdür; gece yarısı ve hydration boyunca senkron tutulur.
Date–
timeZone
string–
locale
Partial<DayPickerLocale>–
dir
"ltr" | "rtl"–
footer
ReactNode–
ÖznitelikAçıklama
data-slot="calendar"CSS'te takvim kökünü hedefleyin.
--cell-sizeGün hücresi boyutu. 36px, dokunmatik ekranlarda 44px.
--cell-radiusGün hücrelerinin ve düğmelerinin köşe yarıçapı.
data-slot="calendar-day"Gün hücreleri. data-selected, data-disabled, data-outside, data-today, data-hidden ve data-focused taşır.
data-previewGün hücrelerinde: üzerine gelinen aralık önizlemesinin başı, ortası veya sonu.
data-range-middleSeçili bir aralığın içindeki gün hücrelerinde.

Her günün içindeki düğme. Kendinizinkini components={{ DayButton }} ile geçin ve stili korumak için bunu yeniden kullanın.

ÖznitelikAçıklama
data-slot="calendar-day-button"CSS'te gün düğmelerini hedefleyin.
data-day2026-10-03 gibi ISO tarihi.
data-todayBugün üzerinde bulunur; dışarıdaki günler hariç.
data-selected-singleAralığın dışında seçili.
data-range-startAralığın ilk günü.
data-range-middleAralığın içindeki bir gün.
data-range-endAralığın son günü.

İstemcide bugünü Date olarak, sunucu tarafı render sırasında undefined döndürür; böylece ondan türetilen sınırlar asla hydration uyuşmazlığına yol açmaz. Gece yarısı güncellenir. useToday kılavuzuna bakın.