ProComponents, templates & AI tooling
HeroUI
27.7k

RangeCalendar 范围日历

基于 React Aria RangeCalendar 的可组合日期范围选择器,包含月份网格、导航与年份选择支持。

引入

import { RangeCalendar } from '@heroui/react';

用法

行程日期, May 2026

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
"use client";

import {RangeCalendar} from "@heroui/react";

export function Basic() {

组件结构

import {RangeCalendar} from '@heroui/react';

export default () => (
  <RangeCalendar aria-label="Trip dates">
    <RangeCalendar.Header>
      <RangeCalendar.Heading />
      <RangeCalendar.NavButton slot="previous" />
      <RangeCalendar.NavButton slot="next" />
    </RangeCalendar.Header>
    <RangeCalendar.Grid>
      <RangeCalendar.GridHeader>
        {(day) => <RangeCalendar.HeaderCell>{day}</RangeCalendar.HeaderCell>}
      </RangeCalendar.GridHeader>
      <RangeCalendar.GridBody>
        {(date) => <RangeCalendar.Cell date={date} />}
      </RangeCalendar.GridBody>
    </RangeCalendar.Grid>
  </RangeCalendar>
)

年份选择

RangeCalendar.YearPickerTriggerRangeCalendar.YearPickerGrid 及其 body/cell 子组件提供一体化的年份导航模式。

行程日期, May 2026

26
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
"use client";

import {RangeCalendar} from "@heroui/react";

export function YearPicker() {

默认值

行程日期, February 2025

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
"use client";

import {RangeCalendar} from "@heroui/react";
import {parseDate} from "@internationalized/date";

受控

行程日期, December 2025

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
已选区间: (无)
"use client";

import type {DateValue} from "@internationalized/date";

import {Button, ButtonGroup, Description, RangeCalendar} from "@heroui/react";

最小与最大日期

行程日期, May 2026

26
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
请在今天与 2026-08-29 之间选择日期。
"use client";

import {Description, RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";

不可用日期

使用 isDateUnavailable 禁用周末、节假日或已被预订的日期等。

行程日期, June 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
29
30
1
2
3
4
5
部分日期不可选
"use client";

import type {DateValue} from "@internationalized/date";

import {Description, RangeCalendar} from "@heroui/react";

允许非连续范围

启用 allowsNonContiguousRanges,允许选择跨越不可用日期的范围。

行程日期, May 2026

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
允许跨不可选日期选择非连续区间
"use client";

import type {DateValue} from "@internationalized/date";

import {Description, RangeCalendar} from "@heroui/react";

禁用

行程日期, May 2026

26
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
区间日历已禁用
"use client";

import {Description, RangeCalendar} from "@heroui/react";

export function Disabled() {

只读

行程日期, May 2026

26
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
区间日历为只读
"use client";

import {Description, RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";

无效

行程日期, June 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
29
30
1
2
3
4
5

最长入住时间为 1 周

"use client";

import type {DateValue} from "@internationalized/date";

import {Description, RangeCalendar} from "@heroui/react";

焦点日期

行程日期, June 2025

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
1
2
3
4
5
6
聚焦: 2025-06-15
"use client";

import type {DateValue} from "@internationalized/date";

import {Button, Description, RangeCalendar} from "@heroui/react";

单元格指示器

你可以自定义 RangeCalendar.Cell 的子节点,并使用 RangeCalendar.CellIndicator 展示活动等元数据。

行程日期, May 2026

26
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
"use client";

import {RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, isToday} from "@internationalized/date";

多个月份

使用 visibleDurationoffset 渲染多个月份网格,适用于预订与规划场景。

行程日期, May to June 2026

May 2026
26
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
June 2026
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
"use client";

import {RangeCalendar} from "@heroui/react";
import {getLocalTimeZone} from "@internationalized/date";
import React from "react";

国际化历法

默认情况下,RangeCalendar 按用户语言环境的历法显示日期。你可以使用 I18nProvider 包裹 RangeCalendar,并通过 Unicode 历法语言扩展 覆盖。

下方示例展示印度历法系统:

行程日期, शक 1948 ज्येष्ठ

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
6
"use client";

import {RangeCalendar} from "@heroui/react";
import {I18nProvider} from "react-aria-components";

说明: onChange 事件始终返回与 valuedefaultValue 相同历法系统中的日期(若未提供值则为公历),与界面展示的本地化格式无关。

实际场景示例

预订区间, May 2026

26
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
不可订日期 周末/不可用
"use client";

import type {DateValue} from "@internationalized/date";

import {Button, RangeCalendar} from "@heroui/react";

样式

传入 Tailwind CSS 类

import {RangeCalendar} from '@heroui/react';

function CustomRangeCalendar() {
  return (
    <RangeCalendar aria-label="Trip dates" className="w-80 rounded-2xl border border-border bg-surface p-3 shadow-sm">
      <RangeCalendar.Header className="pb-3">
        <RangeCalendar.Heading className="text-default" />
        <RangeCalendar.NavButton slot="previous" className="text-default" />
        <RangeCalendar.NavButton slot="next" className="text-default" />
      </RangeCalendar.Header>
      <RangeCalendar.Grid>
        <RangeCalendar.GridHeader>
          {(day) => <RangeCalendar.HeaderCell>{day}</RangeCalendar.HeaderCell>}
        </RangeCalendar.GridHeader>
        <RangeCalendar.GridBody>
          {(date) => <RangeCalendar.Cell date={date} />}
        </RangeCalendar.GridBody>
      </RangeCalendar.Grid>
    </RangeCalendar>
  );
}

自定义组件类

@layer components {
  .range-calendar {
    @apply w-80 rounded-2xl border border-border bg-surface p-3 shadow-sm;
  }

  .range-calendar__heading {
    @apply text-sm font-semibold text-default;
  }

  .range-calendar__cell[data-selected="true"] .range-calendar__cell-button {
    @apply bg-accent text-accent-foreground;
  }
}

CSS 类

RangeCalendar 在 packages/styles/components/range-calendar.csspackages/styles/components/calendar-year-picker.css 中使用以下类:

  • .range-calendar - 根容器。
  • .range-calendar__header - 含导航按钮与标题的头部行。
  • .range-calendar__heading - 当前月份标签。
  • .range-calendar__nav-button - 上一月/下一月导航控件。
  • .range-calendar__grid - 主体日期网格。
  • .range-calendar__grid-header - 星期标题行外层。
  • .range-calendar__grid-body - 日期行外层。
  • .range-calendar__header-cell - 星期标题单元格。
  • .range-calendar__cell - 可交互日期单元格外层。
  • .range-calendar__cell-button - 单元格内的可交互日期按钮。
  • .range-calendar__cell-indicator - 日期单元格内的圆点指示器。
  • .calendar-year-picker__trigger - 年份选择器切换按钮。
  • .calendar-year-picker__trigger-heading - 年份选择触发器内的标题文案。
  • .calendar-year-picker__trigger-indicator - 年份选择触发器内的指示图标。
  • .calendar-year-picker__year-grid - 可选年份的覆盖网格。
  • .calendar-year-picker__year-cell - 单个年份选项。

交互状态

RangeCalendar 同时支持伪类与 React Aria 的 data 属性:

  • 已选中[data-selected="true"]
  • 范围起点[data-selection-start="true"]
  • 范围终点[data-selection-end="true"]
  • 范围内[data-selection-in-range="true"]
  • 今天[data-today="true"]
  • 不可用[data-unavailable="true"]
  • 跨月[data-outside-month="true"]
  • 悬停:hover[data-hovered="true"]
  • 按下:active[data-pressed="true"]
  • 焦点可见:focus-visible[data-focus-visible="true"]
  • 禁用:disabled[data-disabled="true"]

API 参考

RangeCalendar Props

RangeCalendar 继承 React Aria RangeCalendar 的全部 props。

Prop类型默认值描述
valueRangeValue<DateValue> | null-受控的选中范围。
defaultValueRangeValue<DateValue> | null-初始选中范围(非受控)。
onChange(value: RangeValue<DateValue>) => void-选中变化时调用。
focusedValueDateValue-受控的焦点日期。
onFocusChange(value: DateValue) => void-焦点移动到其它日期时调用。
minValueDateValue历法感知的 1900-01-01可选的最早日期。
maxValueDateValue历法感知的 2099-12-31可选的最晚日期。
isDateUnavailable(date: DateValue) => boolean-将日期标记为不可用。
allowsNonContiguousRangesbooleanfalse允许范围跨越不可用日期。
isDisabledbooleanfalse禁用交互与选择。
isReadOnlybooleanfalse内容只读,不可更改选中。
isInvalidbooleanfalse标记为无效以配合校验样式。
visibleDuration{months?: number}{months: 1}可见月份数量。
defaultYearPickerOpenbooleanfalse内置年份选择器的初始展开状态。
isYearPickerOpenboolean-受控的年份选择器展开状态。
onYearPickerOpenChange(isOpen: boolean) => void-年份选择器展开状态变化时调用。

组合部件

组件描述
RangeCalendar.Header导航与标题的头部容器。
RangeCalendar.Heading当前月/年标题。
RangeCalendar.NavButton上一页/下一页导航(slot="previous"slot="next")。
RangeCalendar.Grid单个月的日期网格(多月份布局支持 offset)。
RangeCalendar.GridHeader星期标题容器。
RangeCalendar.GridBody日期单元格主体容器。
RangeCalendar.HeaderCell星期标签单元格。
RangeCalendar.Cell单个日期单元格。
RangeCalendar.CellIndicator用于自定义元数据的可选指示元素。
RangeCalendar.YearPickerTrigger切换年份选择模式的触发器。
RangeCalendar.YearPickerTriggerHeading年份选择触发器内的本地化标题内容。
RangeCalendar.YearPickerTriggerIndicator年份选择触发器内的切换图标。
RangeCalendar.YearPickerGrid年份选择覆盖网格容器。
RangeCalendar.YearPickerGridBody年份网格单元格的 body 渲染器。
RangeCalendar.YearPickerCell单个年份选项单元格。

RangeCalendar.Cell Render Props

RangeCalendar.Cellchildren 为函数时,可使用 React Aria 的渲染参数:

Prop类型描述
formattedDatestring单元格日期的本地化文案。
isSelectedboolean该日期是否已选中。
isSelectionStartboolean是否为选中范围的起点。
isSelectionEndboolean是否为选中范围的终点。
isUnavailableboolean该日期是否不可用。
isDisabledboolean单元格是否禁用。
isOutsideMonthboolean是否属于相邻月份。

支持的历法系统及其标识符完整列表见:

  • @internationalized/date — 各日期组件共用的日期类型(CalendarDateCalendarDateTimeZonedDateTime)与工具函数
  • I18nProvider — 为子树覆盖语言环境
  • useLocale — 读取当前语言环境与书写方向

本页目录