multiselect, radio, checkboxes, tags, lookup, master_detail, file, image,
location, formula, summary, auto_number, user, owner, object, vector, grid,
color, slider, rating, code, avatar, address, geolocation, signature, qrcode,
object-ref, filter-condition, recipient-picker
#3306 落地时按裁决补了「每个注册 widget 校验失败必须携带
aria-invalid」的全注册表守卫(packages/fields/src/__tests__/widget-aria-invalid-registry-e2e.test.tsx,范式同 #3291 的 DOM leak sweep)。真实表单 + 真实 react-hook-form 校验失败(required+null,presence 语义,cloud#972)、先自证 "is required" 消息已渲染再读 aria。实测 46 个注册类型中 29 个在整行 DOM 里找不到任何aria-invalid="true"—— 视觉上有红字报错,屏幕阅读器完全收不到字段处于错误状态:(通过的 17 个:text / textarea / number / boolean / select(#3306 修复)/ date / datetime / time / email / phone / url / currency / percent / password / markdown / html / richtext。)
成因(与 #3222 / #3306 同一失败类,两种形态)
<FormControl>Slot 注入的aria-invalid/aria-describedby)转发到它渲染的真实控件上——没有toDomPropsspread,也不读error槽位。grid):内部有自己的 per-cellaria-invalid,但表单级失败不驱动它。账本与棘轮
这 29 个类型登记在守卫文件的
NOT_YET_DELIVEREDledger 里,且按反方向断言(sweep 证明它们仍未送达):修好任何一个,它的 ledger 行会变红,强制从账本移除、转入正向守卫。账本只能收缩;新 widget 不能悄悄进入账本(新增类型默认走正向断言)。修法(每个 widget 同一范式)
按 #3222/#3306 的纪律:把
toDomProps(props)spread 到 widget 的真实可聚焦控件(注意 Radix 非 DOM Root 会吞掉 aria-*,见 #3306 的SelectTrigger处理),并在 spread 之后写aria-invalid={!!error}(error是 specFieldWidgetPropsSchema的发布槽位)。消息文本仍归<FormMessage/>,widget 只置状态。可分批处理,每批从 ledger 删除对应条目。参考
field:select从不向辅助技术播报校验状态 —— aria-invalid / aria-describedby / aria-required 被 Radix Select.Root 静默丢弃 #3306(select 的修复 + 守卫落地)error,objectui 渲染errorMessage(declared ≠ enforced) #3222(首批 7 个 widget 的同类修复)aria-required从未到达任何输入控件——必填状态只以「可访问名的一部分」存在 #3290(aria-required状态通道)schema="[object Object]"出现在真实输入框上 #3291(sweep 范式与toDomProps白名单)Generated by Claude Code