
UI组件前端【免费下载链接】ariakitToolkit with accessible components, styles, and examples for your next web app项目地址https://gitcode.com/gh_mirrors/ar/ariakit点击查看免费下载Ariakit 的 Form 组件基于 WAI-ARIA Form Role 设计为 React 应用提供了一整套自带无障碍支持的表单交互方案从字段状态管理、浏览器内置校验的接入到自定义校验与异步提交再到错误提示的展示与聚焦。读完本文你将掌握useFormStore、useFormSubmit、useFormValidate等核心 API 的完整用法并能结合源码理解 Ariakit 表单内部的状态流转与无障碍细节直接落地到生产项目。组件与 API 总览Ariakit 的表单体系由一个 store 与一组配套组件组成。store 通过useFormStore创建负责统一管理values字段值、errors错误信息与touched字段是否被触碰过三份核心状态组件则通过storeprop 或上下文拿到 store完成渲染与交互。完整 API 一览useFormStore() useFormContext() useFormValue() useFormValidate() useFormSubmit() FormProvider Form FormGroup FormGroupLabel / FormLabel / FormControl / FormInput / FormCheckbox / FormDescription / FormError / FormPush / FormRemove / /FormGroup FormRadioGroup FormRadio / /FormRadioGroup FormReset / FormSubmit / /Form /FormProviderHookuseFormStore创建表单 storeuseFormContext读取上下文中的 storeuseFormValue订阅单个字段值并在其变化时触发重渲染useFormValidate/useFormSubmit分别向 store 注册校验与提交回调。结构组件FormProvider提供上下文适合 store 不在Form内创建的场景、Form、FormGroup、FormGroupLabel。字段组件FormLabel、FormControl、FormInput、FormCheckbox、FormRadio、FormRadioGroup、FormDescription、FormError。数组字段组件FormPush向数组字段追加值、FormRemove移除指定下标的值。操作组件FormReset、FormSubmit。一个最小可运行示例对应仓库中的 examples/form/index.react.tsximport * as Ariakit from ariakit/react; function Example() { const form Ariakit.useFormStore({ defaultValues: { name: , email: }, }); Ariakit.useFormSubmit(form, async (state) { alert(JSON.stringify(state.values)); }); return ( Ariakit.Form store{form} aria-labelledbyadd-new-participant h2 idadd-new-participantAdd new participant/h2 div classNamefield Ariakit.FormLabel name{form.names.name}Name/Ariakit.FormLabel Ariakit.FormInput name{form.names.name} placeholderJohn Doe required / Ariakit.FormError name{form.names.name} classNameerror / /div div classNamefield Ariakit.FormLabel name{form.names.email}Email/Ariakit.FormLabel Ariakit.FormInput typetext name{form.names.email} placeholderjohndoeexample.com required / Ariakit.FormError name{form.names.email} classNameerror / /div div classNamebuttons Ariakit.FormReset classNamebutton secondary resetReset/Ariakit.FormReset Ariakit.FormSubmit classNamebuttonAdd/Ariakit.FormSubmit /div /Ariakit.Form ); }理解表单 store状态与字段名代理useFormStore是整套表单的枢纽。它在 React 侧封装了底层核心 store核心实现在 packages/ariakit-components/src/form/form-store.ts由以下三份数据驱动状态说明默认值values表单字段的当前值任意嵌套对象{}errors与values结构对应的错误信息DeepPartial{}touched字段是否被触碰过DeepPartialDeepMapT, boolean{}此外还维护了派生状态valid当前是否有效、validating是否正在校验、submitting是否正在提交以及submitSucceed/submitFailed两个计数器分别记录提交成功与失败的次数。store 提供的方法分为几组值操作getValue(name)/setValue(name, value)支持点分路径读取与写入嵌套值pushValue(name, value)/removeValue(name, index)用于数组字段——注意removeValue会用null占位被删除的下标以保持索引稳定详见 form-store.ts提交前如需省略被删除项应自行过滤null。错误操作getError(name)/setError(name, error)/setErrors(errors)其中setErrors可接收函数式更新。触碰状态getFieldTouched(name)/setFieldTouched(name, value)/setTouched(touched)。流程控制onValidate(callback)/validate()、onSubmit(callback)/submit()、reset()。一个非常实用的细节是form.names它是一个基于Proxy的字段名代理form-store.ts。访问form.names.name.first会返回字符串name.first既避免了手写魔法字符串拼错路径又能获得完整的 TypeScript 类型提示同时它支持Symbol.toPrimitive/toString在 React 中作为 children 渲染也不会报错。提交表单注册提交处理器useFormSubmit用于在表单 store 上注册提交处理器。当用户提交表单或代码调用form.submit()时所有已注册的处理器会按注册顺序依次执行。提交处理器可以返回 Promise并且能直接与 store 交互——这意味着我们可以在提交时读取表单values并在失败时调用setErrors把服务端返回的错误展示到界面上const form useFormStore(); useFormSubmit(form, async (state) { const response await fetch(https://jsonplaceholder.typicode.com/posts, { method: POST, body: JSON.stringify(state.values), headers: { Content-type: application/json; charsetUTF-8, }, }); if (!response.ok) { form.setErrors(await response.json()); } });从源码看submit()的完整流程是form-store.ts将submitting置为true并把所有字段的touched一次性置为true调用setAll(values, true)意味着提交后错误会立刻可见先执行校验调用validate()若校验失败则submitFailed 1并返回false校验通过后按注册顺序依次执行所有 submit 回调串行执行以保证顺序可预测见源码中引用的 issue #2282等待下一帧nextFrame即requestAnimationFrame与 100ms 超时的竞速确保隐藏标签页也能推进流程再次检查errors为空则submitSucceed 1并返回true否则视为失败无论成败最终都会在finally中将submitting复位。useFormSubmit内部通过useEvent保持回调引用稳定并监听 store 的items变化来重置回调顺序form-store.ts这样即使字段是懒加载渲染的回调执行顺序依然一致。表单校验内置校验与自定义校验浏览器内置校验Ariakit 完整支持浏览器内置的表单校验。直接在字段上使用required、minLength、maxLength、min、max、type、pattern等原生属性即可获得开箱即用的简单校验。这种方式最大的优势是错误消息由浏览器自动本地化为用户当前语言。但它也有明显局限默认的错误提示 UI 不一定符合无障碍标准样式不可定制且无法精确控制错误提示的显示时机。好在我们可以通过 JavaScript 的Constraint Validation API介入这一过程——这正是FormControl内部做的事情。它让错误消息可以以无障碍、可定制的方式展示出来。在源码中FormControl会通过useFormValidate注册一个校验回调form-control.tsx它会找到与字段名匹配的真实 DOM 元素通过element.form.elements.namedItem(name)在表单内查找等待一个微任务让validity状态就绪然后若element.validity.valid为false就把element.validationMessage即浏览器本地化的错误文案写入 storeuseFormValidate(form, async () { const element getNamedElement(ref, name); if (!element) return; await Promise.resolve(); if (validity in element !element.validity.valid) { form.setError(name, element.validationMessage); } });同时Form组件会渲染noValidate属性form.tsx关闭浏览器默认的原生错误气泡把校验与展示完全交给 store 与组件体系。自定义校验与useFormSubmit类似useFormValidate用来在表单 store 上注册校验处理器。校验在字段被触碰或表单提交时触发。校验回调可以像普通 hook 一样被拆到独立组件中作为 prop 传入实现字段级校验function MyForm() { const form useFormStore({ defaultValues: { name: } }); return ( Form store{form} NameInput store{form} name{form.names.name} / /Form ); } function NameInput({ store, name, ...props }) { useFormValidate(store, () { const value store.getValue(name); if (value.length 3) { store.setError(name, Name must be at least 3 characters long); } }); return FormInput name{name} {...props} /; }validate()的内部实现form-store.ts同样采用串行执行先把validating置为true、清空errors再按注册顺序逐个 await 校验回调最后等待下一帧并依据errors是否为空返回布尔结果。校验与重置的触发时机Form组件提供了几个布尔选项来控制行为源码见 form.tsx选项默认值作用validateOnChangetrue字段值变化时触发校验回调通过useUpdateEffect监听values跳过与初始值相等的时刻validateOnBlurtrue字段失焦时触发校验回调仅当失焦目标确认为本表单字段时autoFocusOnSubmittrue提交后自动聚焦第一个无效字段若为文本类字段还会自动全选文本resetOnSubmittrue提交成功后把表单重置为defaultValuesresetOnUnmountfalse组件卸载时重置表单状态其中autoFocusOnSubmit的实现会遍历按 DOM 位置排序的表单项找到第一个aria-invalidtrue的字段并调用element.focus()form.tsx——这是无障碍表单的关键一环提交失败时屏幕阅读器用户和键盘用户能直接到达出错位置。错误消息的展示FormErrorFormError组件用于渲染单个字段的错误消息默认渲染为div并自动带上rolealertform-error.tsx确保错误出现时能被屏幕阅读器即时播报。它的渲染逻辑有一个值得注意的细节children只有在字段存在错误且字段已被触碰getFieldTouched(name)为true时才会显示form-error.tsx。这意味着在用户离开字段之前校验错误不会打扰输入过程一旦用户触碰过该字段失焦或提交错误就立刻可见。这也与submit()中“提交时将所有字段标记为 touched”的行为互相呼应。样式基于 aria-invalid 定制错误态FormControl是FormInput、FormCheckbox、FormRadio等字段组件的共同基础。当字段无效时它会自动把aria-invalid属性设为trueform-control.tsx判定条件是“存在错误且字段已被触碰”invalid: () !!form.getError(name) form.getFieldTouched(name),因此可以直接用属性选择器定制无效状态下的视觉样式.field[aria-invalidtrue] { /* 例如红色边框 */ border-color: red; }aria-invalid本身也是无障碍标准的一部分屏幕阅读器会在用户进入该字段时播报“无效”状态。此外FormControl还会自动把aria-labelledby指向对应的FormLabel、把aria-describedby拼接FormError与FormDescription的 idform-control.tsx确保标签、错误与描述在无障碍 API 层面正确关联。更多样式技巧可参考仓库中的 Styling 指南。更多无障碍细节FormLabel如果字段是原生input、textarea、select等元素FormLabel渲染为原生label并依赖htmlFor否则渲染为span依靠字段上的aria-labelledby建立关联点击标签仍会把焦点移到字段上form-label.tsx对自定义控件如富文本编辑器尤其友好。FormSubmit渲染原生typesubmit按钮并在submitting期间置为disabled由于默认开启了accessibleWhenDisabled禁用状态下按钮对键盘和屏幕阅读器依然可访问form-submit.tsx。FormControl 与 FormInput 的区别FormInput会自动把value与onChange传给底层元素FormControl则不做这件事适合把表单状态桥接到值不由原生value/onChange控制的自定义组件如编辑器、选择器此时通常配合useFormValue读取值、调用store.setValue写回值。总结Ariakit Form 组件把浏览器内置校验、store 驱动的状态管理、可定制且可访问的错误展示整合为一条完整链路useFormStore管理状态useFormSubmit/useFormValidate以可预测的顺序执行业务回调Form组件接管校验时机、失败聚焦与成功重置FormControl系列字段组件负责把无障碍属性aria-invalid、aria-labelledby、aria-describedby、rolealert自动接好。无论是简单联系人表单还是带数组字段、服务端校验的复杂业务表单这套体系都能在保持无障碍的同时让代码足够简洁。赞分享UI组件前端【免费下载链接】ariakitToolkit with accessible components, styles, and examples for your next web app项目地址https://gitcode.com/gh_mirrors/ar/ariakit点击查看免费下载相关推荐Ariakit Form深度解析无障碍表单状态管理与校验的终极方案Ariakit Form深度解析无障碍表单状态管理与校验的终极方案 Ariakit Form 是 Ariakit 无障碍组件库中专门解决表单问题的核心模块。它UI组件前端Ariakit 实战用 FormRadio 与 FormRadioGroup 构建带自定义校验的无障碍单选表单Ariakit 实战用 FormRadio 与 FormRadioGroup 构建带自定义校验的无障碍单选表单 本文围绕 Ariakit 仓库中的 formUI组件前端React Hook Form V6 实战指南基于 Hook 的表单状态管理与校验React Hook Form V6 实战指南基于 Hook 的表单状态管理与校验 导读 本指南围绕本仓库 docs/README.V6.md https:/前端上一篇一文读懂T5-Base220M参数模型的核心架构与终极优势指南下一篇探索IEEE-1394标准开源文档仓库助力技术开发创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考