Support indeterminate state for Checkbox#512
Open
msmx-mnakagawa wants to merge 6 commits intomasterfrom
Open
Conversation
Extend the `checked` prop to accept string literals (`'checked'`,
`'unchecked'`, `'indeterminate'`) in addition to `boolean`. This lets
consumers control all three checkbox states — checked, unchecked, and
indeterminate — through a single prop, using either boolean or string
form.
The HTML `indeterminate` property is DOM-only (no corresponding HTML
attribute), so it must be set imperatively via a ref. To do this without
breaking the existing `inputRef` prop, the component now uses a merged
ref (`internalRef` + `mergedRef`):
- `internalRef` holds the DOM node for the `useEffect` that toggles
`indeterminate`.
- `mergedRef` forwards the same node to the consumer-supplied `inputRef`,
whether it is a `RefObject` or a callback ref.
A simpler approach (e.g. reading `inputRef.current` directly) would fail
when `inputRef` is omitted or is a callback ref. Dropping `inputRef`
support would break backward compatibility.
Backward compatibility: existing `checked={true}` / `checked={false}`
usage continues to work unchanged. The `CheckboxProps` type uses
`Omit<InputHTMLAttributes, 'checked'>` to avoid a union conflict with
the native `checked?: boolean` from `InputHTMLAttributes`.
Ref: #511
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Checkbox
|
reg-suit detected visual differences. Check this report, and review them. ⚪ 🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵 What do the circles mean?The number of circles represent the number of changed images.🔴 : Changed items, ⚪ : New items, ⚫ : Deleted items, and 🔵 Passed items How can I change the check status?If reviewers approve this PR, the reg context status will be green automatically. |
This reverts commit 033b105.
Replace the `CheckedState` string literal approach (`checked: boolean | 'checked' | 'unchecked' | 'indeterminate'`) with a separate `indeterminate?: boolean` prop, following the DOM `HTMLInputElement.indeterminate` property pattern. When both `checked` and `indeterminate` are true, `indeterminate` takes visual precedence (matching native browser behavior). The `checked` prop type remains `boolean` — no breaking change. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover both combinations: `indeterminate` without `checked`, and `indeterminate` with `checked` (indeterminate takes visual precedence). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The browser resets the DOM `indeterminate` property to `false` on every click. Since the `indeterminate` prop doesn't change, `useEffect([indeterminate])` does not re-run, leaving the DOM out of sync. Intercept `onChange` to re-apply the `indeterminate` DOM property after the consumer's handler runs. The `useEffect` is kept for initial mount and prop-change synchronization. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add
indeterminate?: booleanprop toCheckbox, following the DOMHTMLInputElement.indeterminateproperty pattern.Closes #511
Why
onChangeinterception is neededThe DOM
indeterminateproperty has no corresponding HTML attribute, so React cannot manage it declaratively. We set it imperatively viauseEffect([indeterminate])on mount and when the prop changes.However, the browser resets
indeterminatetofalseon every click. Since the prop value doesn't change (it's stilltrue),useEffectdoes not re-run and the visual state is lost.To solve this,
CheckboxinterceptsonChangeand re-appliesindeterminateafter each click. This dual mechanism ensures:useEffecthandles initial mount and prop changeshandleChangehandles the browser's click-triggered resetTest plan
Defaultstory still works (booleantrue/false)Indeterminatestory renders the indeterminate dash mark for bothindeterminateonly andchecked + indeterminateuseStateworks correctlyControlledWithKnobsstory still worksnpm run type-checkpassesnpm run lintpasses with 0 errors🤖 Generated with Claude Code