Lzh on GitHub
一个用于选择单日、多日或日期范围的日历组件。
此组件依赖于 @internationalized/date 包,该包提供了以区域设置感知的方式表示和操作日期和时间的对象和函数。

用法

使用 v-model 指令来控制选定的日期。

February 2022
30
31
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
1
2
3
4
5
6
7
8
9
10
11
12
Event Date, February 2022
<script setup lang="ts">
const value = ref(new CalendarDate(2022, 2, 3))
</script>

<template>
  <UCalendar v-model="value" />
</template>

当你不需要控制其状态时,使用 default-value prop 来设置初始值。

February 2022
30
31
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
1
2
3
4
5
6
7
8
9
10
11
12
Event Date, February 2022
<script setup lang="ts">
const defaultValue = ref(new CalendarDate(2022, 2, 6))
</script>

<template>
  <UCalendar :default-value="defaultValue" />
</template>

多选

使用 multiple prop 允许选择多个日期。

February 2022
30
31
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
1
2
3
4
5
6
7
8
9
10
11
12
Event Date, February 2022
<script setup lang="ts">
const value = ref([
  new CalendarDate(2022, 2, 4),
  new CalendarDate(2022, 2, 6),
  new CalendarDate(2022, 2, 8)
])
</script>

<template>
  <UCalendar multiple v-model="value" />
</template>

范围选择

使用 range prop 来选择一个日期范围。

Event Date, February 2022
February 2022
30
31
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
1
2
3
4
5
6
7
8
9
10
11
12
<script setup lang="ts">
const value = ref({ start: new CalendarDate(2022, 2, 3), end: new CalendarDate(2022, 2, 20) })
</script>

<template>
  <UCalendar range v-model="value" />
</template>

颜色

使用 color prop 来改变日历的颜色。

February 2026
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Event Date, February 2026
<template>
  <UCalendar color="neutral" />
</template>

尺寸(Size)

使用 size prop 来改变日历的尺寸。

February 2026
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Event Date, February 2026
<template>
  <UCalendar size="xl" />
</template>

禁用

使用 disabled prop 来禁用日历。

February 2026
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Event Date, February 2026
<template>
  <UCalendar disabled />
</template>

月份数量

使用 numberOfMonths prop 来改变日历中显示的月份数量。

February - April 2026
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
3
4
5
6
7
8
9
10
11
29
30
31
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
6
7
8
9
Event Date, February - April 2026
<template>
  <UCalendar :number-of-months="3" />
</template>

月份控制

使用 month-controls prop 来显示月份控制。默认为 true

February 2026
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Event Date, February 2026
<template>
  <UCalendar :month-controls="false" />
</template>

年份控制

使用 year-controls prop 来显示年份控制。默认为 true

February 2026
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Event Date, February 2026
<template>
  <UCalendar :year-controls="false" />
</template>

固定周数

使用 fixed-weeks prop 来以固定周数显示日历。

February 2026
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
Event Date, February 2026
<template>
  <UCalendar :fixed-weeks="false" />
</template>

国际化

使用 locale prop 来改变日历的语言。

2026年2月
26
27
28
29
30
31
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
1
2
3
4
5
6
7
8
Event Date, 2026年2月
<template>
  <UCalendar locale="zh-CN" />
</template>

如果要全局中文化

app.config.ts 里配置:

export default defineAppConfig({
  ui: {
    calendar: {
      locale: 'zh-CN'
    }
  }
})

示例

使用 chip events

使用 Chip 组件为特定日期添加事件。

<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'

const modelValue = shallowRef(new CalendarDate(2022, 1, 10))

function getColorByDate(date: Date) {
  const isWeekend = date.getDay() % 6 == 0
  const isDayMeeting = date.getDay() % 3 == 0

  if (isWeekend) {
    return undefined
  }

  if (isDayMeeting) {
    return 'error'
  }

  return 'success'
}
</script>

<template>
  <UCalendar v-model="modelValue">
    <template #day="{ day }">
      <UChip :show="!!getColorByDate(day.toDate('UTC'))" :color="getColorByDate(day.toDate('UTC'))" size="2xs">
        {{ day.day }}
      </UChip>
    </template>
  </UCalendar>
</template>

使用 disabled dates

使用 is-date-disabled prop 结合一个函数来将特定日期标记为禁用。

<script setup lang="ts">
import type { DateValue } from '@internationalized/date'
import { CalendarDate } from '@internationalized/date'

const modelValue = shallowRef({
  start: new CalendarDate(2022, 1, 1),
  end: new CalendarDate(2022, 1, 9)
})

const isDateDisabled = (date: DateValue) => {
  return date.day >= 10 && date.day <= 16
}
</script>

<template>
  <UCalendar v-model="modelValue" :is-date-disabled="isDateDisabled" range />
</template>

使用不可用日期

使用 is-date-unavailable prop 结合一个函数来将特定日期标记为不可用。

<script setup lang="ts">
import type { DateValue } from '@internationalized/date'
import { CalendarDate } from '@internationalized/date'

const modelValue = shallowRef({
  start: new CalendarDate(2022, 1, 1),
  end: new CalendarDate(2022, 1, 9)
})

const isDateUnavailable = (date: DateValue) => {
  return date.day >= 10 && date.day <= 16
}
</script>

<template>
  <UCalendar v-model="modelValue" :is-date-unavailable="isDateUnavailable" range />
</template>

使用最小/最大日期

使用 min-valuemax-value props 来限制日期范围。

<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'

const modelValue = shallowRef(new CalendarDate(2023, 9, 10))
const minDate = new CalendarDate(2023, 9, 1)
const maxDate = new CalendarDate(2023, 9, 30)
</script>

<template>
  <UCalendar v-model="modelValue" :min-value="minDate" :max-value="maxDate" />
</template>

使用其他日历系统

你可以使用 @internationalized/date 中的其他日历来实现不同的日历系统。

<script lang="ts" setup>
import { CalendarDate, HebrewCalendar } from '@internationalized/date'

const hebrewDate = shallowRef(new CalendarDate(new HebrewCalendar(), 5781, 1, 1))
</script>

<template>
  <UCalendar v-model="hebrewDate" />
</template>
你可以在 @internationalized/date 文档中查看所有可用的日历。

使用外部控制

你可以通过操作 v-model 中传入的日期来通过外部控制日历。

<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'

const date = shallowRef(new CalendarDate(2025, 4, 2))
</script>

<template>
  <div class="flex flex-col gap-4">
    <UCalendar v-model="date" :month-controls="false" :year-controls="false" />

    <div class="flex justify-between gap-4">
      <UButton color="neutral" variant="outline" @click="date = date.subtract({ months: 1 })">
        Prev
      </UButton>

      <UButton color="neutral" variant="outline" @click="date = date.add({ months: 1 })">
        Next
      </UButton>
    </div>
  </div>
</template>

作为日期选择器

使用 ButtonPopover 组件来创建一个日期选择器。

<script setup lang="ts">
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'

const df = new DateFormatter('en-US', {
  dateStyle: 'medium'
})

const modelValue = shallowRef(new CalendarDate(2022, 1, 10))
</script>

<template>
  <UPopover>
    <UButton color="neutral" variant="subtle" icon="i-lucide-calendar">
      {{ modelValue ? df.format(modelValue.toDate(getLocalTimeZone())) : 'Select a date' }}
    </UButton>

    <template #content>
      <UCalendar v-model="modelValue" class="p-2" />
    </template>
  </UPopover>
</template>

作为日期范围选择器

使用 ButtonPopover 组件来创建一个日期范围选择器。

<script setup lang="ts">
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date'

const df = new DateFormatter('en-US', {
  dateStyle: 'medium'
})

const modelValue = shallowRef({
  start: new CalendarDate(2022, 1, 20),
  end: new CalendarDate(2022, 2, 10)
})
</script>

<template>
  <UPopover>
    <UButton color="neutral" variant="subtle" icon="i-lucide-calendar">
      <template v-if="modelValue.start">
        <template v-if="modelValue.end">
          {{ df.format(modelValue.start.toDate(getLocalTimeZone())) }} - {{ df.format(modelValue.end.toDate(getLocalTimeZone())) }}
        </template>

        <template v-else>
          {{ df.format(modelValue.start.toDate(getLocalTimeZone())) }}
        </template>
      </template>
      <template v-else>
        Pick a date
      </template>
    </UButton>

    <template #content>
      <UCalendar v-model="modelValue" class="p-2" :number-of-months="2" range />
    </template>
  </UPopover>
</template>

API

Props

Prop Default Type
as

'div'

any

The element or component this component should render as.

nextYearIcon

appConfig.ui.icons.chevronDoubleRight

string

The icon to use for the next year control.

nextYear

ButtonProps

Configure the next year button. { color: 'neutral', variant: 'ghost' }

nextMonthIcon

appConfig.ui.icons.chevronRight

string

The icon to use for the next month control.

nextMonth

ButtonProps

Configure the next month button. { color: 'neutral', variant: 'ghost' }

prevYearIcon

appConfig.ui.icons.chevronDoubleLeft

string

The icon to use for the previous year control.

prevYear

ButtonProps

Configure the prev year button. { color: 'neutral', variant: 'ghost' }

prevMonthIcon

appConfig.ui.icons.chevronLeft

string

The icon to use for the previous month control.

prevMonth

ButtonProps

Configure the prev month button. { color: 'neutral', variant: 'ghost' }

color

'primary'

"error" | "primary" | "secondary" | "success" | "info" | "warning" | "neutral"

size

'md'

"md" | "xs" | "sm" | "lg" | "xl"

range

boolean

Whether or not a range of dates can be selected

multiple

boolean

Whether or not multiple dates can be selected

monthControls

true

boolean

Show month controls

yearControls

true

boolean

Show year controls

defaultValue

CalendarDate | CalendarDateTime | ZonedDateTime | DateRange | DateValue[]

modelValue

null | CalendarDate | CalendarDateTime | ZonedDateTime | DateRange | DateValue[]

disabled

boolean

Whether or not the calendar is disabled

defaultPlaceholder

CalendarDate | CalendarDateTime | ZonedDateTime

The default placeholder date

placeholder

CalendarDate | CalendarDateTime | ZonedDateTime

The placeholder date, which is used to determine what month to display when no date is selected. This updates as the user navigates the calendar and can be used to programmatically control the calendar view

allowNonContiguousRanges

boolean

When combined with isDateUnavailable, determines whether non-contiguous ranges, i.e. ranges containing unavailable dates, may be selected.

pagedNavigation

boolean

This property causes the previous and next buttons to navigate by the number of months displayed at once, rather than one month

preventDeselect

boolean

Whether or not to prevent the user from deselecting a date without selecting another date first

maximumDays

number

The maximum number of days that can be selected in a range

weekStartsOn

0 | 2 | 1 | 3 | 4 | 5 | 6

The day of the week to start the calendar on

weekdayFormat

"narrow" | "short" | "long"

The format to use for the weekday strings provided via the weekdays slot prop

fixedWeeks

true

boolean

Whether or not to always display 6 weeks in the calendar

maxValue

CalendarDate | CalendarDateTime | ZonedDateTime

The maximum date that can be selected

minValue

CalendarDate | CalendarDateTime | ZonedDateTime

The minimum date that can be selected

numberOfMonths

number

The number of months to display at once

readonly

boolean

Whether or not the calendar is readonly

initialFocus

boolean

If true, the calendar will focus the selected day, today, or the first day of the month depending on what is visible when the calendar is mounted

isDateDisabled

(date: DateValue): boolean

A function that returns whether or not a date is disabled

isDateUnavailable

(date: DateValue): boolean

A function that returns whether or not a date is unavailable

isDateHighlightable

(date: DateValue): boolean

A function that returns whether or not a date is hightable

nextPage

(placeholder: DateValue): DateValue

A function that returns the next page of the calendar. It receives the current placeholder as an argument inside the component.

prevPage

(placeholder: DateValue): DateValue

A function that returns the previous page of the calendar. It receives the current placeholder as an argument inside the component.

disableDaysOutsideCurrentView

boolean

Whether or not to disable days outside the current view.

fixedDate

"start" | "end"

Which part of the range should be fixed

ui

{ root?: ClassNameValue; header?: ClassNameValue; body?: ClassNameValue; heading?: ClassNameValue; grid?: ClassNameValue; ... 5 more ...; cellTrigger?: ClassNameValue; }

Slots

Slot Type
heading

{ value: string; }

day

Pick<CalendarCellTriggerProps, "day">

week-day

{ day: string; }

Emits

Event Type
update:modelValue

DateValue | DateRange | DateValue[] | null

update:placeholder

[date: DateValue] & [date: DateValue]

update:startValue

DateValue

Theme

app.config.ts
export default defineAppConfig({
  ui: {
    calendar: {
      slots: {
        root: '',
        header: 'flex items-center justify-between',
        body: 'flex flex-col space-y-4 pt-4 sm:flex-row sm:space-x-4 sm:space-y-0',
        heading: 'text-center font-medium truncate mx-auto',
        grid: 'w-full border-collapse select-none space-y-1 focus:outline-none',
        gridRow: 'grid grid-cols-7 place-items-center',
        gridWeekDaysRow: 'mb-1 grid w-full grid-cols-7',
        gridBody: 'grid',
        headCell: 'rounded-md',
        cell: 'relative text-center',
        cellTrigger: [
          'm-0.5 relative flex items-center justify-center rounded-full whitespace-nowrap focus-visible:ring-2 focus:outline-none data-disabled:text-muted data-unavailable:line-through data-unavailable:text-muted data-unavailable:pointer-events-none data-[selected]:text-inverted data-today:font-semibold data-[outside-view]:text-muted',
          'transition'
        ]
      },
      variants: {
        color: {
          primary: {
            headCell: 'text-primary',
            cellTrigger: 'focus-visible:ring-primary data-[selected]:bg-primary data-today:not-data-[selected]:text-primary data-[highlighted]:bg-primary/20 hover:not-data-[selected]:bg-primary/20'
          },
          secondary: {
            headCell: 'text-secondary',
            cellTrigger: 'focus-visible:ring-secondary data-[selected]:bg-secondary data-today:not-data-[selected]:text-secondary data-[highlighted]:bg-secondary/20 hover:not-data-[selected]:bg-secondary/20'
          },
          success: {
            headCell: 'text-success',
            cellTrigger: 'focus-visible:ring-success data-[selected]:bg-success data-today:not-data-[selected]:text-success data-[highlighted]:bg-success/20 hover:not-data-[selected]:bg-success/20'
          },
          info: {
            headCell: 'text-info',
            cellTrigger: 'focus-visible:ring-info data-[selected]:bg-info data-today:not-data-[selected]:text-info data-[highlighted]:bg-info/20 hover:not-data-[selected]:bg-info/20'
          },
          warning: {
            headCell: 'text-warning',
            cellTrigger: 'focus-visible:ring-warning data-[selected]:bg-warning data-today:not-data-[selected]:text-warning data-[highlighted]:bg-warning/20 hover:not-data-[selected]:bg-warning/20'
          },
          error: {
            headCell: 'text-error',
            cellTrigger: 'focus-visible:ring-error data-[selected]:bg-error data-today:not-data-[selected]:text-error data-[highlighted]:bg-error/20 hover:not-data-[selected]:bg-error/20'
          },
          neutral: {
            headCell: 'text-highlighted',
            cellTrigger: 'focus-visible:ring-inverted data-[selected]:bg-inverted data-today:not-data-[selected]:text-highlighted data-[highlighted]:bg-inverted/20 hover:not-data-[selected]:bg-inverted/10'
          }
        },
        size: {
          xs: {
            heading: 'text-xs',
            cell: 'text-xs',
            headCell: 'text-[10px]',
            cellTrigger: 'size-7',
            body: 'space-y-2 pt-2'
          },
          sm: {
            heading: 'text-xs',
            headCell: 'text-xs',
            cell: 'text-xs',
            cellTrigger: 'size-7'
          },
          md: {
            heading: 'text-sm',
            headCell: 'text-xs',
            cell: 'text-sm',
            cellTrigger: 'size-8'
          },
          lg: {
            heading: 'text-md',
            headCell: 'text-md',
            cellTrigger: 'size-9 text-md'
          },
          xl: {
            heading: 'text-lg',
            headCell: 'text-lg',
            cellTrigger: 'size-10 text-lg'
          }
        }
      },
      defaultVariants: {
        size: 'md',
        color: 'primary'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        calendar: {
          slots: {
            root: '',
            header: 'flex items-center justify-between',
            body: 'flex flex-col space-y-4 pt-4 sm:flex-row sm:space-x-4 sm:space-y-0',
            heading: 'text-center font-medium truncate mx-auto',
            grid: 'w-full border-collapse select-none space-y-1 focus:outline-none',
            gridRow: 'grid grid-cols-7 place-items-center',
            gridWeekDaysRow: 'mb-1 grid w-full grid-cols-7',
            gridBody: 'grid',
            headCell: 'rounded-md',
            cell: 'relative text-center',
            cellTrigger: [
              'm-0.5 relative flex items-center justify-center rounded-full whitespace-nowrap focus-visible:ring-2 focus:outline-none data-disabled:text-muted data-unavailable:line-through data-unavailable:text-muted data-unavailable:pointer-events-none data-[selected]:text-inverted data-today:font-semibold data-[outside-view]:text-muted',
              'transition'
            ]
          },
          variants: {
            color: {
              primary: {
                headCell: 'text-primary',
                cellTrigger: 'focus-visible:ring-primary data-[selected]:bg-primary data-today:not-data-[selected]:text-primary data-[highlighted]:bg-primary/20 hover:not-data-[selected]:bg-primary/20'
              },
              secondary: {
                headCell: 'text-secondary',
                cellTrigger: 'focus-visible:ring-secondary data-[selected]:bg-secondary data-today:not-data-[selected]:text-secondary data-[highlighted]:bg-secondary/20 hover:not-data-[selected]:bg-secondary/20'
              },
              success: {
                headCell: 'text-success',
                cellTrigger: 'focus-visible:ring-success data-[selected]:bg-success data-today:not-data-[selected]:text-success data-[highlighted]:bg-success/20 hover:not-data-[selected]:bg-success/20'
              },
              info: {
                headCell: 'text-info',
                cellTrigger: 'focus-visible:ring-info data-[selected]:bg-info data-today:not-data-[selected]:text-info data-[highlighted]:bg-info/20 hover:not-data-[selected]:bg-info/20'
              },
              warning: {
                headCell: 'text-warning',
                cellTrigger: 'focus-visible:ring-warning data-[selected]:bg-warning data-today:not-data-[selected]:text-warning data-[highlighted]:bg-warning/20 hover:not-data-[selected]:bg-warning/20'
              },
              error: {
                headCell: 'text-error',
                cellTrigger: 'focus-visible:ring-error data-[selected]:bg-error data-today:not-data-[selected]:text-error data-[highlighted]:bg-error/20 hover:not-data-[selected]:bg-error/20'
              },
              neutral: {
                headCell: 'text-highlighted',
                cellTrigger: 'focus-visible:ring-inverted data-[selected]:bg-inverted data-today:not-data-[selected]:text-highlighted data-[highlighted]:bg-inverted/20 hover:not-data-[selected]:bg-inverted/10'
              }
            },
            size: {
              xs: {
                heading: 'text-xs',
                cell: 'text-xs',
                headCell: 'text-[10px]',
                cellTrigger: 'size-7',
                body: 'space-y-2 pt-2'
              },
              sm: {
                heading: 'text-xs',
                headCell: 'text-xs',
                cell: 'text-xs',
                cellTrigger: 'size-7'
              },
              md: {
                heading: 'text-sm',
                headCell: 'text-xs',
                cell: 'text-sm',
                cellTrigger: 'size-8'
              },
              lg: {
                heading: 'text-md',
                headCell: 'text-md',
                cellTrigger: 'size-9 text-md'
              },
              xl: {
                heading: 'text-lg',
                headCell: 'text-lg',
                cellTrigger: 'size-10 text-lg'
              }
            }
          },
          defaultVariants: {
            size: 'md',
            color: 'primary'
          }
        }
      }
    })
  ]
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import uiPro from '@nuxt/ui-pro/vite'

export default defineConfig({
  plugins: [
    vue(),
    uiPro({
      ui: {
        calendar: {
          slots: {
            root: '',
            header: 'flex items-center justify-between',
            body: 'flex flex-col space-y-4 pt-4 sm:flex-row sm:space-x-4 sm:space-y-0',
            heading: 'text-center font-medium truncate mx-auto',
            grid: 'w-full border-collapse select-none space-y-1 focus:outline-none',
            gridRow: 'grid grid-cols-7 place-items-center',
            gridWeekDaysRow: 'mb-1 grid w-full grid-cols-7',
            gridBody: 'grid',
            headCell: 'rounded-md',
            cell: 'relative text-center',
            cellTrigger: [
              'm-0.5 relative flex items-center justify-center rounded-full whitespace-nowrap focus-visible:ring-2 focus:outline-none data-disabled:text-muted data-unavailable:line-through data-unavailable:text-muted data-unavailable:pointer-events-none data-[selected]:text-inverted data-today:font-semibold data-[outside-view]:text-muted',
              'transition'
            ]
          },
          variants: {
            color: {
              primary: {
                headCell: 'text-primary',
                cellTrigger: 'focus-visible:ring-primary data-[selected]:bg-primary data-today:not-data-[selected]:text-primary data-[highlighted]:bg-primary/20 hover:not-data-[selected]:bg-primary/20'
              },
              secondary: {
                headCell: 'text-secondary',
                cellTrigger: 'focus-visible:ring-secondary data-[selected]:bg-secondary data-today:not-data-[selected]:text-secondary data-[highlighted]:bg-secondary/20 hover:not-data-[selected]:bg-secondary/20'
              },
              success: {
                headCell: 'text-success',
                cellTrigger: 'focus-visible:ring-success data-[selected]:bg-success data-today:not-data-[selected]:text-success data-[highlighted]:bg-success/20 hover:not-data-[selected]:bg-success/20'
              },
              info: {
                headCell: 'text-info',
                cellTrigger: 'focus-visible:ring-info data-[selected]:bg-info data-today:not-data-[selected]:text-info data-[highlighted]:bg-info/20 hover:not-data-[selected]:bg-info/20'
              },
              warning: {
                headCell: 'text-warning',
                cellTrigger: 'focus-visible:ring-warning data-[selected]:bg-warning data-today:not-data-[selected]:text-warning data-[highlighted]:bg-warning/20 hover:not-data-[selected]:bg-warning/20'
              },
              error: {
                headCell: 'text-error',
                cellTrigger: 'focus-visible:ring-error data-[selected]:bg-error data-today:not-data-[selected]:text-error data-[highlighted]:bg-error/20 hover:not-data-[selected]:bg-error/20'
              },
              neutral: {
                headCell: 'text-highlighted',
                cellTrigger: 'focus-visible:ring-inverted data-[selected]:bg-inverted data-today:not-data-[selected]:text-highlighted data-[highlighted]:bg-inverted/20 hover:not-data-[selected]:bg-inverted/10'
              }
            },
            size: {
              xs: {
                heading: 'text-xs',
                cell: 'text-xs',
                headCell: 'text-[10px]',
                cellTrigger: 'size-7',
                body: 'space-y-2 pt-2'
              },
              sm: {
                heading: 'text-xs',
                headCell: 'text-xs',
                cell: 'text-xs',
                cellTrigger: 'size-7'
              },
              md: {
                heading: 'text-sm',
                headCell: 'text-xs',
                cell: 'text-sm',
                cellTrigger: 'size-8'
              },
              lg: {
                heading: 'text-md',
                headCell: 'text-md',
                cellTrigger: 'size-9 text-md'
              },
              xl: {
                heading: 'text-lg',
                headCell: 'text-lg',
                cellTrigger: 'size-10 text-lg'
              }
            }
          },
          defaultVariants: {
            size: 'md',
            color: 'primary'
          }
        }
      }
    })
  ]
})