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

用法

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

2022 年 2 月
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
事件日期, 2022 年 2 月
<script setup lang="ts">
const value = ref(new CalendarDate(2022, 2, 3))
</script>

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

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

2022 年 2 月
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
事件日期, 2022 年 2 月
<script setup lang="ts">
const defaultValue = ref(new CalendarDate(2022, 2, 6))
</script>

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

多选

使用 multiple 属性以允许多选。

2022 年 2 月
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
事件日期, 2022 年 2 月
<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 属性选择一个日期范围。

事件日期, 2022 年 2 月
2022 年 2 月
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 属性来改变日历的颜色。

2025 年 4 月
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
10
事件日期, 2025 年 4 月
<template>
  <UCalendar color="neutral" />
</template>

尺寸

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

2025 年 4 月
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
10
事件日期, 2025 年 4 月
<template>
  <UCalendar size="xl" />
</template>

禁用

使用 disabled 属性禁用日历。

2025 年 4 月
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
10
事件日期, 2025 年 4 月
<template>
  <UCalendar disabled />
</template>

月数

使用 numberOfMonths 属性来改变日历中显示的月数。

2025 年 4 月 - 6 月
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
10
27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
6
7
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
10
11
12
事件日期, 2025 年 4 月 - 6 月
<template>
  <UCalendar :number-of-months="3" />
</template>

月份控件

使用 month-controls 属性显示月份控件。默认为 true

2025 年 4 月
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
10
事件日期, 2025 年 4 月
<template>
  <UCalendar :month-controls="false" />
</template>

年份控件

使用 year-controls 属性显示年份控件。默认为 true

2025 年 4 月
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
10
事件日期, 2025 年 4 月
<template>
  <UCalendar :year-controls="false" />
</template>

固定周数

使用 fixed-weeks 属性以固定周数显示日历。

2025 年 4 月
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
事件日期, 2025 年 4 月
<template>
  <UCalendar :fixed-weeks="false" />
</template>

示例

带事件标签

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

2022 年 1 月
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
29
30
31
1
2
3
4
5
事件日期, 2022 年 1 月
<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>

带禁用日期

使用带有函数的 is-date-disabled 属性来标记特定日期为禁用状态。

事件日期, 2022 年 1 月
2022 年 1 月
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
29
30
31
1
2
3
4
5
<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 属性来标记特定日期为不可用状态。

事件日期, 2022 年 1 月
2022 年 1 月
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
29
30
31
1
2
3
4
5
<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 属性来限制日期。

2023 年 9 月
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
29
30
1
2
3
4
5
6
7
事件日期, 2023 年 9 月
<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 中的其他日历来实现不同的日历系统。

Tishri 5781
24
25
26
27
28
29
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
事件日期, Tishri 5781
<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 的日期来使用外部控件控制日历。

2025 年 4 月
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
10
事件日期, 2025 年 4 月
<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

属性

属性默认值类型
as

'div'

any

此组件应渲染为何种元素或组件。

nextYearIcon

appConfig.ui.icons.chevronDoubleRight

string

用于下一年控件的图标。

nextYear

ButtonProps

配置“下一年”按钮。 { color: 'neutral', variant: 'ghost' }

nextMonthIcon

appConfig.ui.icons.chevronRight

string

用于控制下一月的图标。

nextMonth

ButtonProps

配置下一月按钮。 { color: 'neutral', variant: 'ghost' }

prevYearIcon

appConfig.ui.icons.chevronDoubleLeft

string

用于控制上一年的图标。

prevYear

ButtonProps

配置上一年按钮。 { color: 'neutral', variant: 'ghost' }

prevMonthIcon

appConfig.ui.icons.chevronLeft

string

用于控制上一月的图标。

prevMonth

ButtonProps

配置上一月按钮。 { color: 'neutral', variant: 'ghost' }

颜色

'primary'

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

尺寸

'md'

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

range

boolean

是否可以选择日期范围

multiple

boolean

是否可以选择多个日期

月份控件

true

boolean

显示月份控件

年份控件

true

boolean

显示年份控件

defaultValue

CalendarDate | CalendarDateTime | ZonedDateTime | DateRange | DateValue[]

modelValue

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

defaultPlaceholder

CalendarDate | CalendarDateTime | ZonedDateTime

默认占位符日期

placeholder

CalendarDate | CalendarDateTime | ZonedDateTime

占位符日期,用于在未选择日期时确定显示哪个月份。当用户导航日历时,此值会更新,并且可以用于程序化控制日历视图。

allowNonContiguousRanges

boolean

isDateUnavailable 结合使用时,确定是否可以选择非连续范围,即包含不可用日期的范围。

pagedNavigation

boolean

此属性使上一个和下一个按钮按一次显示的月份数量进行导航,而不是按一个月进行导航。

preventDeselect

boolean

是否阻止用户在未先选择另一个日期的情况下取消选择日期。

weekStartsOn

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

日历的周起始日。

weekdayFormat

"narrow" | "short" | "long"

通过 `weekdays` 插槽属性提供的星期字符串的格式。

固定周数

true

boolean

是否始终在日历中显示 6 周。

maxValue

CalendarDate | CalendarDateTime | ZonedDateTime

可选择的最大日期。

minValue

CalendarDate | CalendarDateTime | ZonedDateTime

可选择的最小日期。

月数

number

一次显示的月份数量。

禁用

boolean

日历是否被禁用。

readonly

boolean

日历是否只读。

initialFocus

boolean

如果为 true,日历在挂载时将根据可见情况聚焦选定的日期、今天或当月的第一天。

isDateDisabled

(date: DateValue): boolean

一个函数,返回日期是否被禁用。

isDateUnavailable

(date: DateValue): boolean

一个函数,返回日期是否不可用。

nextPage

(placeholder: DateValue): DateValue

一个函数,返回日历的下一页。它在组件内部接收当前占位符作为参数。

prevPage

(placeholder: DateValue): DateValue

一个函数,返回日历的上一页。它在组件内部接收当前占位符作为参数。

ui

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

插槽

插槽类型
heading

{ value: string; }

day

Pick<CalendarCellTriggerProps, "day">

week-day

{ day: string; }

事件

事件类型
update:modelValue

[date: DateValue | DateRange | DateValue[] | null | undefined]

update:placeholder

[date: DateValue] & [date: DateValue]

update:startValue

[date: DateValue | undefined]

主题

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',
        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-inverted 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',
            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-inverted 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',
            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-inverted 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'
          }
        }
      }
    })
  ]
})