Found while implementing #6780 (PR #6801), which added an onBlur arm to four
type="number" widgets. Filed rather than folded in: repairing it is a
behaviour change outside that card's ruling.
What
CurrencyField writes onBlur={handleBlur} AFTER the {...toDomProps(props)}
spread, so it OVERRIDES any onBlur a host supplied.
onBlur is a declared DOM pass-through key — it is named in
FieldWidgetDomProps (packages/fields/src/widgets/types.ts) and in
SDUI_DOM_PASS_THROUGH_KEYS (packages/core/src/utils/dom-props.ts), and
toDomProps forwards it. So this is the DECLARED-BUT-NOT-DELIVERED class
#3290 / #3222 — a key the contract promises that never reaches the DOM.
TagsField has the same shape (onBlur={() => addTag(draft)} after its spread).
Why it is LATENT today, not an active defect
Measured on d06059f24: no host in this repo passes onBlur to a field
widget. The form renderers do not, and the data-table inline editor
deliberately uses a document-level pointerdown listener instead, with a
comment saying the injected widgets have no blur handler
(packages/components/src/renderers/complex/data-table.tsx). So nothing is
being dropped right now — it would bite the first host that relies on the
declared key, e.g. react-hook-form's touched/onBlur validation mode.
Why PR #6801 did not just repair it
The three widgets that gained an onBlur there (Percent, Number, Geolocation)
DO compose the host handler, because for them a bare handler would have been a
new regression. CurrencyField is different: composing changes behaviour that has
been in place since long before that card, and could start firing onBlur-mode
validation on currency fields that never saw it. That is an unmeasured change
outside the ruling, so it was left exactly as it was and written down here.
Suggested shape
The same one PR #6801 used for the other three:
const domProps = toDomProps(props);
const handleBlur = (e) => { ...existing...; domProps.onBlur?.(e); };
plus a pin that a host onBlur survives — PR #6801 has one for the other three
in NumberInputWidgets.badInputAnnounce.test.tsx.
Generated by Claude Code
Found while implementing #6780 (PR #6801), which added an
onBlurarm to fourtype="number"widgets. Filed rather than folded in: repairing it is abehaviour change outside that card's ruling.
What
CurrencyFieldwritesonBlur={handleBlur}AFTER the{...toDomProps(props)}spread, so it OVERRIDES any
onBlura host supplied.onBluris a declared DOM pass-through key — it is named inFieldWidgetDomProps(packages/fields/src/widgets/types.ts) and inSDUI_DOM_PASS_THROUGH_KEYS(packages/core/src/utils/dom-props.ts), andtoDomPropsforwards it. So this is the DECLARED-BUT-NOT-DELIVERED class#3290 / #3222 — a key the contract promises that never reaches the DOM.
TagsFieldhas the same shape (onBlur={() => addTag(draft)}after its spread).Why it is LATENT today, not an active defect
Measured on
d06059f24: no host in this repo passesonBlurto a fieldwidget. The form renderers do not, and the data-table inline editor
deliberately uses a document-level
pointerdownlistener instead, with acomment saying the injected widgets have no blur handler
(
packages/components/src/renderers/complex/data-table.tsx). So nothing isbeing dropped right now — it would bite the first host that relies on the
declared key, e.g. react-hook-form's touched/onBlur validation mode.
Why PR #6801 did not just repair it
The three widgets that gained an
onBlurthere (Percent, Number, Geolocation)DO compose the host handler, because for them a bare handler would have been a
new regression. CurrencyField is different: composing changes behaviour that has
been in place since long before that card, and could start firing onBlur-mode
validation on currency fields that never saw it. That is an unmeasured change
outside the ruling, so it was left exactly as it was and written down here.
Suggested shape
The same one PR #6801 used for the other three:
plus a pin that a host
onBlursurvives — PR #6801 has one for the other threein
NumberInputWidgets.badInputAnnounce.test.tsx.Generated by Claude Code