Skip to content

feat(Checkbox): indeterminate checkboxes#3123

Merged
codecademydev merged 17 commits intomainfrom
cass-gm-1187
Jul 11, 2025
Merged

feat(Checkbox): indeterminate checkboxes#3123
codecademydev merged 17 commits intomainfrom
cass-gm-1187

Conversation

@dreamwasp
Copy link
Copy Markdown
Contributor

@dreamwasp dreamwasp commented Jun 26, 2025

Overview

Adds an indeterminate state to Checkbox

I structured these based on guidance from Mark to use a native checkbox instead of using aria-checked.

PR Checklist

  • Related to designs: gm-1187
  • Related to JIRA ticket: [gm-1187]
  • I have run this code to verify it works
  • This PR includes unit tests for the code change
  • This PR includes testing instructions tests for the code change
  • The alpha package of this PR is passing end-to-end tests in all relevant Codecademy repositories

Testing Instructions

  1. Go to Checkbox story
  2. Checkout the new docs
  3. Put on VO and hear the checkbox being announced as indeterminate
  4. Check out the branch locally and test the new types (checked + indeterminate cannot be true at the same time)

PR Links and Envs

Repository PR Link
Monolith Monolith PR
Mono Mono PR

@nx-cloud
Copy link
Copy Markdown

nx-cloud bot commented Jun 26, 2025

View your CI Pipeline Execution ↗ for commit 8a51bd3


☁️ Nx Cloud last updated this comment at 2025-07-11 14:33:43 UTC

@dreamwasp dreamwasp marked this pull request as ready for review July 8, 2025 12:46
@dreamwasp dreamwasp requested a review from a team as a code owner July 8, 2025 12:46
Copy link
Copy Markdown
Contributor

@LinKCoding LinKCoding left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, I left some thoughts/suggestions, mostly around SB stuff.

I looked over the stories and VO sounds great!


expect(onChange).toHaveBeenCalled();
});
it('sets the input indeterminate state when the prop is passed', () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it help to also check that checked is also false (or !true? falsey?) here when indeterminate is true?

E.g. as a safeguard in case types get changed?

import { BaseInputProps } from '../types';
import { CheckboxCheckedUnion, CheckboxLabelUnion } from './types';

/** Something will happen here */
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover comment

Comment on lines +147 to +156
function syncedRefs(element: HTMLInputElement | null) {
intRef.current = element;
if (ref) {
if (typeof ref === 'object') {
ref.current = element;
} else {
ref(element);
}
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: when would ref be passed in as a function?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

callback refs are sometimes used in animations and other things - here's some react official docs with fancy examples: Manipulating the DOM with Refs

);
};

const NestedCheckboxExample: React.FC = () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you export this (and update its name to NestedCheckboxes or whatever the .mdx file expects)

You can have the code inside the "Show code" box, e.g.
image

That way you don't need to add the code snippet after this canvas


<Canvas of={CheckboxStories.NestedCheckboxes} />

```tsx
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see comment on exporting the example directly — but I don't think you need to add this


<Canvas of={CheckboxStories.Indeterminate} />

`indeterminate` is used for Checkboxes that are the header of a list of checkboxes. When clicked, all of its child checkboxes should be selected or unselected. Clicking on only some of the child checkboxes should make the header checkbox show the indeterminate state.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeterminate is used for Checkboxes that are the header of a list of checkboxes.

I think calling the parent a "header" might be confusing — maybe sticking with "parent" and "nested" like in your example works. Something like:

indeterminate is used for a Checkbox that is the parent of a list of checkboxes.
or GPT has this suggestion:

indeterminate is used for a parent Checkbox that represents the combined state of a group of nested checkboxes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When clicked, all of its child checkboxes should be selected or unselected. Clicking on only some of the child checkboxes should make the header checkbox show the indeterminate state.

Maybe: "When the parent checkbox is checked or blank, all of its child checkboxes should be selected or unselected, respectively. The indeterminate state is shown when only some of the child checkboxes are checked."

@codecademydev
Copy link
Copy Markdown
Collaborator

🚀 Styleguide deploy preview ready!

https://687120c6da19cdff71d8ada1--gamut-preview.netlify.app

Deploy Logs

@codecademydev
Copy link
Copy Markdown
Collaborator

📬Published Alpha Packages:

@codecademy/gamut@65.1.0-alpha.8a51bd.0
@codecademy/gamut-kit@0.6.521-alpha.8a51bd.0
@codecademy/styleguide@76.0.2-alpha.8a51bd.0

@dreamwasp dreamwasp added the Ship It :shipit: Ready 2 ship label Jul 11, 2025
@codecademydev codecademydev merged commit 66ab4f7 into main Jul 11, 2025
21 of 22 checks passed
@codecademydev codecademydev removed the Ship It :shipit: Ready 2 ship label Jul 11, 2025
@codecademydev codecademydev deleted the cass-gm-1187 branch July 11, 2025 14:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants