DatePicker 日期选择器
基于 React Aria DatePicker,通过 DateField 与 Calendar 组合的可组合日期选择器
用法
import { DatePicker, DateField, Calendar, Label } from '@lenso/ui';此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";
/** Adapted from the pinned HeroUI v3.2.6 basic.json. Copyright NextUI Inc. Apache-2.0. Local RAC label and StyleX replace source Label and utility classes. */import { Calendar, DateField, DatePicker } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";
const styles = stylex.create({ field: { width: 288 } });export function Basic() { return ( <DatePicker xstyle={styles.field} name="date"> <DatePicker.Label>Date</DatePicker.Label> <DateField.Group fullWidth> <DateField.Input>{(segment) => <DateField.Segment segment={segment} />}</DateField.Input> <DateField.Suffix> <DatePicker.Trigger> <DatePicker.TriggerIndicator /> </DatePicker.Trigger> </DateField.Suffix> </DateField.Group> <DatePicker.Popover> <Calendar aria-label="Event date"> <Calendar.Header> <Calendar.YearPickerTrigger> <Calendar.YearPickerTriggerHeading /> <Calendar.YearPickerTriggerIndicator /> </Calendar.YearPickerTrigger> <Calendar.NavButton slot="previous" /> <Calendar.NavButton slot="next" /> </Calendar.Header> <Calendar.Grid> <Calendar.GridHeader> {(day) => <Calendar.HeaderCell>{day}</Calendar.HeaderCell>} </Calendar.GridHeader> <Calendar.GridBody>{(date) => <Calendar.Cell date={date} />}</Calendar.GridBody> </Calendar.Grid> <Calendar.YearPickerGrid> <Calendar.YearPickerGridBody> {({ year }) => <Calendar.YearPickerCell year={year} />} </Calendar.YearPickerGridBody> </Calendar.YearPickerGrid> </Calendar> </DatePicker.Popover> </DatePicker> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
组件结构
DatePicker 采用组合优先 API。显式组合 DateField 与 Calendar 以控制结构与样式。
import {Calendar, DateField, DatePicker, Label} from '@lenso/ui';
export default () => ( <DatePicker> <Label /> <DateField.Group> <DateField.Input> {(segment) => <DateField.Segment segment={segment} />} </DateField.Input> <DateField.Suffix> <DatePicker.Trigger> <DatePicker.TriggerIndicator /> </DatePicker.Trigger> </DateField.Suffix> </DateField.Group> <DatePicker.Popover> <Calendar aria-label="Choose date"> <Calendar.Header> <Calendar.YearPickerTrigger> <Calendar.YearPickerTriggerHeading /> <Calendar.YearPickerTriggerIndicator /> </Calendar.YearPickerTrigger> <Calendar.NavButton slot="previous" /> <Calendar.NavButton slot="next" /> </Calendar.Header> <Calendar.Grid> <Calendar.GridHeader> {(day) => <Calendar.HeaderCell>{day}</Calendar.HeaderCell>} </Calendar.GridHeader> <Calendar.GridBody>{(date) => <Calendar.Cell date={date} />}</Calendar.GridBody> </Calendar.Grid> </Calendar> </DatePicker.Popover> </DatePicker>)示例
禁用
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";/** HeroUI v3.2.6 adapted example. Copyright NextUI Inc. Apache-2.0. */export { Disabled } from "./scenarios";Local adaptation source above. Derived from HeroUI v3.2.6 source.
受控组件
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";/** HeroUI v3.2.6 adapted example. Copyright NextUI Inc. Apache-2.0. */export { Controlled } from "./scenarios";Local adaptation source above. Derived from HeroUI v3.2.6 source.
表单校验
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";/** HeroUI v3.2.6 adapted example. Copyright NextUI Inc. Apache-2.0. */export { WithValidation } from "./scenarios";Local adaptation source above. Derived from HeroUI v3.2.6 source.
格式选项
使用 granularity、hourCycle、hideTimeZone、shouldForceLeadingZeros 等 props 控制 DatePicker 值的显示方式。
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";/** Adapted from HeroUI v3.2.6 format-options.json. Copyright NextUI Inc. Apache-2.0. */import { DatePicker, TimeField } from "@lenso/ui";import { getLocalTimeZone, parseDate, parseZonedDateTime, type DateValue,} from "@internationalized/date";import { useMemo, useState } from "react";import * as stylex from "@stylexjs/stylex";import { PickerCalendar, PickerInput } from "./parts";import { FormatControls, formatStyles, type Granularity, type HourCycle } from "./format-controls";
export function FormatOptions() { const [granularity, setGranularity] = useState<Granularity>("minute"); const [hourCycle, setHourCycle] = useState<HourCycle>(12); const [hideTimeZone, setHideTimeZone] = useState(false); const [shouldForceLeadingZeros, setShouldForceLeadingZeros] = useState(false); const timeGranularity = granularity !== "day" ? granularity : undefined; const defaultValue = useMemo<DateValue>( () => granularity === "day" ? parseDate("2026-02-03") : parseZonedDateTime(`2026-02-03T08:45:00[${getLocalTimeZone()}]`), [granularity], ); return ( <div {...stylex.props(formatStyles.stack)}> <DatePicker key={granularity} xstyle={formatStyles.field} defaultValue={defaultValue} granularity={granularity} hourCycle={hourCycle} hideTimeZone={hideTimeZone} shouldForceLeadingZeros={shouldForceLeadingZeros} name="date" > {({ state }) => ( <> <DatePicker.Label>Date and time</DatePicker.Label> <PickerInput /> <DatePicker.Popover xstyle={formatStyles.popover}> <PickerCalendar /> {timeGranularity && ( <div {...stylex.props(formatStyles.timeRow)}> <span {...stylex.props(formatStyles.label)}>Time</span> <TimeField aria-label="Time" granularity={timeGranularity} hourCycle={hourCycle} hideTimeZone={hideTimeZone} name="time" shouldForceLeadingZeros={shouldForceLeadingZeros} value={state.timeValue} onChange={(value) => { if (value) state.setTimeValue(value); }} > <TimeField.Group variant="secondary"> <TimeField.Input> {(segment) => <TimeField.Segment segment={segment} />} </TimeField.Input> </TimeField.Group> </TimeField> </div> )} </DatePicker.Popover> </> )} </DatePicker> <FormatControls {...{ granularity, setGranularity, hourCycle, setHourCycle, hideTimeZone, setHideTimeZone, shouldForceLeadingZeros, setShouldForceLeadingZeros, }} /> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
表单示例
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";/** HeroUI v3.2.6 adapted example. Copyright NextUI Inc. Apache-2.0. */export { FormExample } from "./scenarios";Local adaptation source above. Derived from HeroUI v3.2.6 source.
自定义指示器
未提供 children 时,DatePicker.TriggerIndicator 渲染默认 IconCalendar。传入 children 可替换。
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";/** HeroUI v3.2.6 adapted example. Copyright NextUI Inc. Apache-2.0. */export { WithCustomIndicator } from "./scenarios";Local adaptation source above. Derived from HeroUI v3.2.6 source.
渲染函数
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";/** Adapted from HeroUI v3.2.6 render-function.json. Copyright NextUI Inc. Apache-2.0. RAC 1.21 native DOM render functions preserve props, refs and input semantics. */import { DateField, DatePicker } from "@lenso/ui";import { PickerCalendar, styles } from "./parts";
export function RenderFunction() { return ( <DatePicker xstyle={styles.field} name="date" render={(props) => <div {...props} data-custom="date-picker" />} > <DatePicker.Label render={(props) => <span {...props} data-custom="date-picker-label" />}> Date </DatePicker.Label> <DateField.Group fullWidth render={(props) => <div {...props} data-custom="date-field-group" />} > <DateField.Input render={(props) => <div {...props} data-custom="date-field-input" />}> {(segment) => ( <DateField.Segment render={(props) => <span {...props} data-custom="date-field-segment" />} segment={segment} /> )} </DateField.Input> <DateField.Suffix> <DatePicker.Trigger render={(props) => <button {...props} data-custom="date-picker-trigger" />} > <DatePicker.TriggerIndicator /> </DatePicker.Trigger> </DateField.Suffix> </DateField.Group> <DatePicker.Popover> <PickerCalendar /> </DatePicker.Popover> </DatePicker> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
国际化日历
默认情况下,DatePicker 使用用户 locale 的日历系统显示日期。可用 I18nProvider 包裹并设置 Unicode 日历 locale 扩展 覆盖。
以下示例展示印度日历系统:
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";/** HeroUI v3.2.6 adapted example. Copyright NextUI Inc. Apache-2.0. */export { InternationalCalendar } from "./scenarios";Local adaptation source above. Derived from HeroUI v3.2.6 source.
Note: 无论显示的 locale 如何,onChange 事件始终返回与 value 或 defaultValue 相同日历系统的日期(未提供 value 时为 Gregorian)。这确保应用逻辑在单一日历系统下一致运行,同时仍可按用户偏好格式显示日期。
完整支持的日历系统及其标识符列表请参阅:
自定义样式
Tailwind CSS
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";/** HeroUI v3.2.6 adapted example. Copyright NextUI Inc. Apache-2.0. */export { CustomStyles } from "./scenarios";Local adaptation source above. Derived from HeroUI v3.2.6 source.
全局 CSS
使用 @layer components 自定义 DatePicker 基础类。
@layer components { .date-picker { @apply inline-flex flex-col gap-1; }
.date-picker__trigger { @apply inline-flex items-center justify-between; }
.date-picker__trigger-indicator { @apply text-muted; }
.date-picker__popover { @apply min-w-[var(--trigger-width)] p-0; }}样式参考
HeroUI 遵循 BEM 命名以便复用自定义。
CSS 类
DatePicker 在 packages/styles/components/date-picker.css 中使用以下类:
.date-picker- 根包裹层.date-picker__trigger- 打开 popover 的触发器部分.date-picker__trigger-indicator- 默认/自定义指示器 slot.date-picker__popover- Popover 内容包裹层
交互状态
DatePicker 支持 React Aria data 属性与伪状态:
- Open:触发器上
[data-open="true"] - Disabled:触发器上
[data-disabled="true"]或[aria-disabled="true"] - Focus visible:触发器上
:focus-visible或[data-focus-visible="true"] - Hover:触发器上
:hover或[data-hovered="true"]
API 参考
DatePicker
DatePicker 继承 React Aria DatePicker 的所有 props。
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
value | DateValue | null | - | 受控选中日期值 |
defaultValue | DateValue | null | - | 非受控模式下的默认选中值 |
onChange | (value: DateValue | null) => void | - | 选中日期变化时调用 |
isOpen | boolean | - | 受控 popover 打开状态 |
defaultOpen | boolean | false | 初始 popover 打开状态 |
onOpenChange | (isOpen: boolean) => void | - | popover 打开状态变化时调用 |
isDisabled | boolean | false | 禁用日期选择与触发器交互 |
isInvalid | boolean | - | 标记字段为无效以显示校验状态 |
minValue | DateValue | - | 最小可选日期 |
maxValue | DateValue | - | 最大可选日期 |
name | string | - | HTML 表单提交时使用的 name |
children | ReactNode | (values: DatePickerRenderProps) => ReactNode | - | 组合内容或 render 函数 |
render | DOMRenderFunction<keyof React.JSX.IntrinsicElements, DatePickerRenderProps> | - | 使用自定义 render 函数覆盖默认 DOM 元素 |
Composition Parts
| Component | Description |
|---|---|
DatePicker.Root | 根 date picker 容器与状态所有者 |
DatePicker.Trigger | 触发按钮,通常渲染在 DateField.Suffix 内 |
DatePicker.TriggerIndicator | 带默认日历图标的指示器 slot |
DatePicker.Popover | Calendar 内容的 Popover 包裹层 |
Related packages
@internationalized/date— 所有日期组件使用的日期类型(CalendarDate、CalendarDateTime、ZonedDateTime)与工具I18nProvider— 为子树覆盖 localeuseLocale— 读取当前 locale 与布局方向