RangeCalendar 范围日历

按月展示与选择日期区间。

日历, 2026年9月
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
11

值:2026-09-04 至 2026-09-12

'use client'

import { useState } from 'react'
import { RangeCalendar, Stack, Text, type DateRangeValue } from '@hina-ui/react'

export default function Demo() {
  const [range, setRange] = useState<DateRangeValue | null>({
    start: '2026-09-04',
    end: '2026-09-12',
  })

  return (
    <Stack gap="sm" align="start">
      <RangeCalendar value={range} onValueChange={setRange} />
      <Text tone="muted" size="sm">
        值:{range ? `${range.start ?? '空'} 至 ${range.end ?? '空'}` : '空'}
      </Text>
    </Stack>
  )
}
tsx

用法

import { RangeCalendar } from '@hina-ui/react'
ts

范围日历与 Calendar 共用同一副网格、标题与月份、年份视图,区别在于选的是一段区间:点击一个日期作为开始,再点击另一个日期作为结束。开始与结束显示为实心格,中间的日期连成一条浅色带。value / onValueChange 绑定 { start, end } 对象,两个字段都是 YYYY-MM-DD 格式的 ISO 8601 字符串,与 DateRangeField 相同;没有值时为 null。

日历, 2026年9月
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
11

值:空

'use client'

import { useState } from 'react'
import { RangeCalendar, Stack, Text, type DateRangeValue } from '@hina-ui/react'

export default function Demo() {
  const [range, setRange] = useState<DateRangeValue | null>(null)

  return (
    <Stack gap="sm" align="start">
      <RangeCalendar value={range} onValueChange={setRange} placeholder="2026-09-01" />
      <Text tone="muted" size="sm">
        值:{range ? `${range.start ?? '空'} 至 ${range.end ?? '空'}` : '空'}
      </Text>
    </Stack>
  )
}
tsx

示例

范围

min 与 max 限定可选范围,范围之外的日期禁用。maximumDays 限制区间最多包含的天数:选定开始日期后,超出天数的日期禁用,区间完成后恢复。

日历, 2026年9月
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
11
'use client'

import { useState } from 'react'
import { RangeCalendar, type DateRangeValue } from '@hina-ui/react'

export default function Demo() {
  const [range, setRange] = useState<DateRangeValue | null>({
    start: '2026-09-10',
    end: '2026-09-14',
  })

  return (
    <RangeCalendar
      value={range}
      onValueChange={setRange}
      min="2026-09-07"
      max="2026-09-25"
      maximumDays={7}
    />
  )
}
tsx

不可选的日期

unavailable 接收 YYYY-MM-DD 字符串并返回该日期是否不可选,不可选的日期显示删除线。区间不能跨过不可选的日期。

日历, 2026年9月
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
11
'use client'

import { useState } from 'react'
import { RangeCalendar, type DateRangeValue } from '@hina-ui/react'

const weekend = (value: string) => [0, 6].includes(new Date(`${value}T00:00`).getDay())

export default function Demo() {
  const [range, setRange] = useState<DateRangeValue | null>({
    start: '2026-09-07',
    end: '2026-09-11',
  })

  return <RangeCalendar value={range} onValueChange={setRange} unavailable={weekend} />
}
tsx

尺寸

size 有 sm、md、lg 三档,与 Calendar 的同档尺寸相同。

日历, 2026年9月
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
11
日历, 2026年9月
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
11
日历, 2026年9月
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
11
import { RangeCalendar, Stack } from '@hina-ui/react'

const range = { start: '2026-09-04', end: '2026-09-12' }

export default function Demo() {
  return (
    <Stack gap="lg" align="start">
      <RangeCalendar size="sm" defaultValue={range} />
      <RangeCalendar size="md" defaultValue={range} />
      <RangeCalendar size="lg" defaultValue={range} />
    </Stack>
  )
}
tsx

状态

readOnly 只读,仍然可以用键盘浏览;disabled 禁用整个日历。

日历, 2026年9月
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
11
日历, 2026年9月
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
11
import { RangeCalendar, Inline } from '@hina-ui/react'

const range = { start: '2026-09-04', end: '2026-09-12' }

export default function Demo() {
  return (
    <Inline gap="lg" align="start">
      <RangeCalendar defaultValue={range} readonly />
      <RangeCalendar defaultValue={range} disabled />
    </Inline>
  )
}
tsx

行为

  • 第一次点击确定开始日期,此时值是 { start, end: null };第二次点击确定结束日期。区间确定后再点击任意日期,会以它为开始重新选择。
  • 选定开始日期后,悬停或者用方向键移动到其他日期时,中间的日期先显示预览带。
  • 结束日期早于开始日期时,两者自动对调。
  • 键盘操作、月份与年份视图、翻页与 placeholder 都与 Calendar 相同。

无障碍

  • 根元素带有语言包给出的名称与当前月份,网格是 role="grid",区间内的每一格都带 aria-selected。
  • 整个网格只占一个 Tab 停靠点,焦点在日期之间用方向键移动;聚焦环只在键盘操作时出现。

API

Props

属性
类型
默认值
说明
value
DateRangeValue | null
null
选中的区间,两端都是 YYYY-MM-DD
placeholder
string
当月
显示的月份,可受控
min
string
—
可选范围的下限
max
string
—
可选范围的上限
maximumDays
number
—
区间最多包含的天数
unavailable
(date: string) => boolean
—
判定某一天是否不可选
weekStartsOn
0 | 1 | 2 | 3 | 4 | 5 | 6
随语言
一周从周几开始
weekdayFormat
'narrow' | 'short'
'narrow'
星期名称的格式
fixedWeeks
boolean
true
是否固定显示六周
size
'sm' | 'md' | 'lg'
'md'
尺寸
autoFocus
boolean
false
挂载时是否聚焦开始日期
readOnly
boolean
false
是否只读
disabled
boolean
false
是否禁用
className
string
—
追加至根元素的类名

DateRangeValue 是 { start: string | null; end: string | null },可以从包入口导入。

回调

回调
参数
说明
onValueChange
value: DateRangeValue | null
区间变化
onPlaceholderChange
value: string
显示的月份变化,参数是该视图内的日期