ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Base UI Progress 组件 API 完整指南:Root / Track / Indicator / Value / Label 的类型体系与无障碍实现解析

Base UI Progress 组件 API 完整指南:Root / Track / Indicator / Value / Label 的类型体系与无障碍实现解析 Base UI Progress 组件 API 完整指南Root / Track / Indicator / Value / Label 的类型体系与无障碍实现解析【免费下载链接】base-uiUnstyled UI components for building accessible web apps and design systems. From the creators of Radix, Floating UI, and Material UI.项目地址: https://gitcode.com/GitHub_Trending/ba/base-uiBase UI本仓库即其base-ui/react源码与文档是一套无样式unstyledReact 组件库由 Radix、Floating UI 与 Material UI 的创建者开发Progress进度条正是其中将「任务完成度展示」与「无障碍语义」完全内置的组件之一。本文以仓库中的 Progress 类型参考文档/react/components/progress/types.md) 为骨架结合 ProgressRoot 源码 与各子部件的实现完整讲解Progress.Root、Progress.Track、Progress.Indicator、Progress.Value、Progress.Label五个部件的全部 Props、状态类型State、数据属性Data Attributes与导出类型并给出可直接运行的示例代码。读完本文你将能够精确配置进度条的数值区间、格式化、无障碍朗读文本与状态驱动的样式并理解其内部如何统一计算完成状态。Progress 组件总体概览Progress 组件采用复合组件Compound Component模式由一个Root统管状态与 ARIA 语义其余部件通过 Context 消费同一份状态从而保证「可见文本、aria-valuenow、指示条宽度」三者始终同步。组件渲染的元素如下部件默认渲染元素职责Progress.Rootdiv聚合所有部件向屏幕阅读器提供任务完成状态roleprogressbarProgress.Trackdiv容纳进度指示条Progress.Indicatordiv可视化呈现任务完成度Progress.Valuespan展示当前数值的文本元素Progress.Labelspan进度条的无障碍标签所有部件在 npm 上统一通过base-ui/react包的Progress命名空间导出见 packages/react/src/progress/index.ts 与 index.parts.ts引用方式为import { Progress } from base-ui/react/progress;官方文档页位于 docs/src/app/(docs)/react/components/progress/page.mdx/react/components/progress/page.mdx)其 hero 示例同时提供了 CSS Modules 与 Tailwind 两个版本可直接作为起步模板CSS Modules 版本/react/components/progress/demos/hero/css-modules/index.tsx)、Tailwind 版本/react/components/progress/demos/hero/tailwind/index.tsx)。Progress.Root状态中枢与 ARIA 语义来源Root是整个组件树中唯一需要传值的部件。它渲染div并带有roleprogressbar向屏幕阅读器暴露当前进度。Root PropsProgress.Root的完整 Props 如下value为必填项其余均可选Prop类型默认值说明value*number \| null-当前值。当value为null时组件进入不确定indeterminate状态aria-valuetextstring-为aria-valuenow提供用户友好名称的字符串getAriaValueText(formattedValue: string, value: number \| null) string-返回当前进度值人类可读文本替代方案的函数localeIntl.LocalesArgument用户运行时的 locale使用Intl.NumberFormat格式化数值时所用的 localeminnumber0最小值maxnumber100最大值formatIntl.NumberFormatOptions-格式化数值的选项classNamestring \| ((state: Progress.Root.State) string \| undefined)-应用于元素的 CSS 类或根据组件状态返回类的函数styleReact.CSSProperties \| ((state: Progress.Root.State) React.CSSProperties \| undefined)-应用于元素的样式或根据组件状态返回样式对象的函数renderReactElement \| ((props: HTMLProps, state: Progress.Root.State) ReactElement)-将组件的 HTML 元素替换为其他标签或与另一组件组合接受ReactElement或返回元素的函数Root 状态机value → status 的推导逻辑在 ProgressRoot.tsx 中status的推导规则清晰可见value null或任何非有限数值如NaN、Infinity→ 状态为indeterminate否则先调用valueToPercent(value, min, max)将值归一化为百分比再clamp到0–100clampedValue max→ 状态为complete完成其余情况 → 状态为progressing进行中。let status: ProgressStatus indeterminate; // ... if (value ! null Number.isFinite(value)) { const rawPercentage valueToPercent(value, min, max); percentageValue clamp(Number.isNaN(rawPercentage) ? 0 : rawPercentage, 0, 100); clampedValue clamp(value, min, max); status clampedValue max ? complete : progressing; }这里的巧妙之处在于由于完成判断基于clampedValue max无论min/max如何配置而不只是默认的 0–100「完成」语义都准确成立。aria-valuenow使用 clamp 后的值可见文本与指示条宽度也基于同一套归一化结果三者天然同步。Root 生成的 ARIA 属性从 ProgressRoot.tsx 的 defaultProps 可以看到Root会自动产出完整的可访问性语义const defaultProps: HTMLProps { aria-labelledby: labelId, aria-valuemax: max, aria-valuemin: min, aria-valuenow: clampedValue ?? undefined, aria-valuetext: getAriaValueText ? getAriaValueText(formattedValue, value) : defaultAriaValueText, role: progressbar, // ... };其中aria-valuetext的取值优先级为若传入getAriaValueText函数则使用其返回值formattedValue为格式化后的字符串value为原始未 clamp 的数值否则使用defaultAriaValueText——indeterminate状态下为字符串indeterminate progress否则为格式化后的百分比文本。此外Root内部还注册了一个不可见的span rolepresentation带visuallyHidden样式用于强制 NVDA 朗读标签这是源码中针对无障碍问题 #4184 的专门修复可作为实现细节参考。Root 的格式化逻辑默认情况下formattedValue采用百分比格式formatNumber(percentageValue / 100, locale, { style: percent })一旦传入format选项则改为formatNumber(clampedValue, locale, format)例如可格式化为「3 / 5」之类的自定义形态。locale与format都透传给Intl.NumberFormat相关工具实现在 packages/utils/src/formatNumber.ts。Progress.Track容纳指示条Track渲染div职责是「包含进度指示条」。它本身不持有任何额外逻辑仅通过useProgressRootContext()消费Root的状态用于渲染状态数据属性与状态驱动样式源码见 ProgressTrack.tsx。Track PropsProp类型默认值说明classNamestring \| ((state: Progress.Track.State) string \| undefined)-CSS 类或根据状态返回类的函数styleReact.CSSProperties \| ((state: Progress.Track.State) React.CSSProperties \| undefined)-样式或根据状态返回样式对象的函数renderReactElement \| ((props: HTMLProps, state: Progress.Track.State) ReactElement)-替换 HTML 元素或与其他组件组合Progress.Indicator可视化完成度Indicator渲染div用于「可视化呈现任务完成度」。它从 Context 中读取percentageValue归一化到 0–100 的百分比并据此生成内联样式见 ProgressIndicator.tsxconst indicatorStyle: React.CSSProperties percentageValue null ? {} : { insetInlineStart: 0, height: inherit, width: ${percentageValue}%, };要点当进度不确定percentageValue null时不输出任何宽度样式宽度完全交给你的 CSS 处理例如动画循环确定状态下width直接等于归一化百分比height: inherit使其跟随Track的高度insetInlineStart: 0保证在 RTL 下从起始边填充。Indicator Props与Track相同仅className、style、render三个均支持基于Progress.Indicator.State的状态函数形式。Progress.Value展示当前数值Value渲染span负责展示当前数值文本且自带aria-hidden: true因为数值信息已由Root的aria-valuenow/aria-valuetext承担避免屏幕阅读器重复朗读见 ProgressValue.tsx。Value PropsProp类型默认值说明children((formattedValue: string \| null, value: number \| null) React.ReactNode) \| null-渲染函数接收格式化值与原始值返回要展示的节点classNamestring \| ((state: Progress.Value.State) string \| undefined)-同前styleReact.CSSProperties \| ((state: Progress.Value.State) React.CSSProperties \| undefined)-同前renderReactElement \| ((props: HTMLProps, state: Progress.Value.State) ReactElement)-同前默认不传children时直接显示格式化后的文本indeterminate状态下显示为null不渲染文本。若传入函数形式Progress.Value {(formattedValue, value) 当前进度${formattedValue}} /Progress.Value此时formattedValue在不确定状态下为字符串indeterminate确定状态下为格式化文本value为Root传入的原始值可能是null。Progress.Label无障碍标签Label渲染span为进度条提供可访问标签。它通过useRegisteredLabelId生成/注册一个id该id会回传给Root成为Root上aria-labelledby的取值从而让进度条与标签建立无障碍关联见 ProgressLabel.tsx。组件自带rolepresentation避免额外的语义干扰。Label Props同样只有className、style、render三项支持状态函数形式另外可传标准id属性覆盖自动生成的 id。状态类型与数据属性统一的 styling 契约Progress.Status五个部件共享同一份状态类型ProgressRoot.tsx#L106type ProgressStatus indeterminate | progressing | complete;Root.State、Value.State、Indicator.State、Track.State、Label.State均为{ status: ProgressStatus }的同一结构各子部件通过extends ProgressRootState复用例如 ProgressIndicator.tsx#L47。Data Attributes状态驱动的样式挂钩Root通过 stateAttributesMapping.ts 将status映射为数据属性并且所有五个部件都会同步渲染相同的数据属性由同一个 mapping 驱动因此你可以仅针对Root或任意子部件书写状态样式Attribute出现条件data-complete进度已完成clampedValue max时存在data-indeterminate进度处于不确定状态时存在data-progressing进度进行中时存在.Progress[data-indeterminate] .Indicator { animation: progress-indeterminate 1s linear infinite; } .Progress[data-complete] .Indicator { background-color: var(--success-color); }测试 ProgressRoot.test.tsx 明确验证了「所有部件在状态循环中保持数据属性同步」这一契约可作为行为预期依据。类型导出体系命名空间与 Canonical TypesProgress的类型组织采用「命名空间导出 顶层别名」双轨制。导出分组如下Progress.RootProgress.Root、Progress.Root.State、Progress.Root.PropsProgress.TrackProgress.Track、Progress.Track.State、Progress.Track.PropsProgress.IndicatorProgress.Indicator、Progress.Indicator.State、Progress.Indicator.PropsProgress.ValueProgress.Value、Progress.Value.State、Progress.Value.PropsProgress.LabelProgress.Label、Progress.Label.State、Progress.Label.PropsDefault顶层导出Progress.Status、ProgressStatus、ProgressRootState、ProgressRootProps、ProgressIndicatorState、ProgressIndicatorProps、ProgressLabelState、ProgressLabelProps、ProgressTrackState、ProgressTrackProps、ProgressValueState、ProgressValueProps其中Default分组即「Canonical Types」规范类型文档约定——当Progress命名空间已被导入时优先使用Progress.X形式否则使用顶层别名如ProgressRootProps。两者的完整映射关系为CanonicalAliasProgress.Root.StateProgressRootStateProgress.Root.PropsProgressRootPropsProgress.Track.StateProgressTrackStateProgress.Track.PropsProgressTrackPropsProgress.Indicator.StateProgressIndicatorStateProgress.Indicator.PropsProgressIndicatorPropsProgress.Value.StateProgressValueStateProgress.Value.PropsProgressValuePropsProgress.Label.StateProgressLabelStateProgress.Label.PropsProgressLabelPropsProgress.StatusProgressStatus完整可运行示例结合上述 API一个带状态驱动的完整示例可对照 Tailwind hero 示例/react/components/progress/demos/hero/tailwind/index.tsx) 与 CSS Modules 示例/react/components/progress/demos/hero/css-modules/index.tsx)use client; import * as React from react; import { Progress } from base-ui/react/progress; export default function ExampleProgress() { const [value, setValue] React.useState(20); // 模拟进度变化 React.useEffect(() { const interval setInterval(() { setValue((current) Math.min(100, Math.round(current Math.random() * 25))); }, 1000); return () clearInterval(interval); }, []); return ( Progress.Root classNamegrid w-60 max-w-full grid-cols-2 gap-y-2 value{value} getAriaValueText{(formattedValue) 导出进度 ${formattedValue}} Progress.Label classNametext-sm text-neutral-950 dark:text-white 导出数据 /Progress.Label Progress.Value classNametext-right text-sm text-neutral-950 dark:text-white / Progress.Track classNamecol-span-2 h-1 overflow-hidden bg-neutral-200 dark:bg-neutral-800 Progress.Indicator classNamebg-neutral-950 transition-[width] duration-500 dark:bg-white / /Progress.Track /Progress.Root ); }几点实操建议不确定状态将value设为null或任意非有限数值组件自动进入indeterminate此时aria-valuenow不输出、aria-valuetext为indeterminate progress、Indicator不注入宽度样式可结合data-indeterminate编写循环动画自定义区间如进度区间为 0–500传入min{0} max{500}Indicator宽度与aria-valuenow仍会正确归一化且value max时自动进入complete状态状态驱动样式className/style支持函数形式接收{ status }状态对象例如className{(state) state.status complete ? done : }也可以在 CSS 中直接利用data-complete/data-indeterminate/data-progressing属性选择器。小结Base UI 的 Progress 组件通过「单一Root状态源 Context 分发 统一状态属性映射」的设计将数值计算、ARIA 语义、格式化输出与样式挂钩收敛为一套自洽的 API五个部件职责分明、类型完整每个部件都配套导出State与Props类型并提供了getAriaValueText、locale、format等面向本地化与无障碍的扩展点。无论在真实业务中实现上传/下载进度还是在设计系统中构建状态驱动的指示器这套 API 都可以作为无样式进度的标准实现范式。【免费下载链接】base-uiUnstyled UI components for building accessible web apps and design systems. From the creators of Radix, Floating UI, and Material UI.项目地址: https://gitcode.com/GitHub_Trending/ba/base-ui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表