| 一 | 二 | 三 | 四 | 五 | 六 | 日 |
|---|---|---|---|---|---|---|
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。
| 一 | 二 | 三 | 四 | 五 | 六 | 日 |
|---|---|---|---|---|---|---|
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 限制区间最多包含的天数:选定开始日期后,超出天数的日期禁用,区间完成后恢复。
| 一 | 二 | 三 | 四 | 五 | 六 | 日 |
|---|---|---|---|---|---|---|
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
尺寸
size 有 sm、md、lg 三档,与 Calendar 的同档尺寸相同。
| 一 | 二 | 三 | 四 | 五 | 六 | 日 |
|---|---|---|---|---|---|---|
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 |
| 一 | 二 | 三 | 四 | 五 | 六 | 日 |
|---|---|---|---|---|---|---|
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 |
| 一 | 二 | 三 | 四 | 五 | 六 | 日 |
|---|---|---|---|---|---|---|
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 禁用整个日历。
| 一 | 二 | 三 | 四 | 五 | 六 | 日 |
|---|---|---|---|---|---|---|
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 |
| 一 | 二 | 三 | 四 | 五 | 六 | 日 |
|---|---|---|---|---|---|---|
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 | 显示的月份变化,参数是该视图内的日期 |