You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Raised by Claude's automated review on PR #218, discussed and decided 2026-07-06.
Button.tsx/IconButton.tsx and Input.tsx/TextArea.tsx all merge a caller-supplied accessibilityState with the component's own computed disabled value, but the caller's value currently wins when there's a conflict:
In all four, if a caller passes accessibilityState={{ disabled: true }} while the component's own disabled prop is false (or vice versa), the caller's value overwrites the component's own computed one.
Decision
The component's own disabled should always win, not the caller's. Rationale: disabled isn't just a label — it drives real behavior (editable, styling). If the caller's accessibilityState.disabled can disagree with that, a screen reader user can be told a field is disabled while it's actually fully interactive (or vice versa), which specifically misleads the exact audience this accessibility feature exists to serve. No realistic legitimate use case was found for letting a caller override just disabled this way.
This does not apply to other accessibilityState keys (selected, expanded, checked, etc.) — those should stay fully caller-overridable, since they don't have a competing "real" computed value the way disabled does.
Fix
Flip the spread order in all four files so the component's own disabled is applied last, e.g.:
```diff
Direct fix needed: `Button.tsx`, `IconButton.tsx` (Button.Icon), `Input.tsx`, `TextArea.tsx`
Fixed automatically: `TextField.tsx` and `Search.tsx` both wrap `Input` and forward `accessibilityState` through, so fixing `Input.tsx` covers them too
Background
Raised by Claude's automated review on PR #218, discussed and decided 2026-07-06.
Button.tsx/IconButton.tsxandInput.tsx/TextArea.tsxall merge a caller-suppliedaccessibilityStatewith the component's own computeddisabledvalue, but the caller's value currently wins when there's a conflict:Button.tsx/IconButton.tsx:{ disabled: disabled ?? false, ...pressableProps.accessibilityState }Input.tsx:{ disabled, ...rest.accessibilityState }TextArea.tsx:{ disabled, ...userAccessibilityState }In all four, if a caller passes
accessibilityState={{ disabled: true }}while the component's owndisabledprop isfalse(or vice versa), the caller's value overwrites the component's own computed one.Decision
The component's own
disabledshould always win, not the caller's. Rationale:disabledisn't just a label — it drives real behavior (editable, styling). If the caller'saccessibilityState.disabledcan disagree with that, a screen reader user can be told a field is disabled while it's actually fully interactive (or vice versa), which specifically misleads the exact audience this accessibility feature exists to serve. No realistic legitimate use case was found for letting a caller override justdisabledthis way.This does not apply to other
accessibilityStatekeys (selected,expanded,checked, etc.) — those should stay fully caller-overridable, since they don't have a competing "real" computed value the waydisableddoes.Fix
Flip the spread order in all four files so the component's own
disabledis applied last, e.g.:```diff
```
Scope
Plan