Skip to content

Conversation

aresnik11
Copy link
Contributor

@aresnik11 aresnik11 commented Sep 8, 2025

Overview

This PR introduces comprehensive nested checkbox functionality to the GridForm and ConnectedForm components, allowing for hierarchical checkbox selections with proper indeterminate states and accessibility support.

Features Added

ConnectedNestedCheckboxes component

  • New ConnectedNestedCheckboxes component and types for use within ConnectedForm contexts
  • Supports infinite levels of nesting with proper state management
  • Automatically expands parent default selections to include all descendants
  • Proper indeterminate state handling for partial selections

GridFormNestedCheckboxInput Component

  • New GridFormNestedCheckboxInput component and types for use within GridForm contexts
  • Supports the same nested functionality as ConnectedNestedCheckboxes

Utility Functions

  • flattenOptions() - Converts nested option structure to flat array with level metadata
  • calculateStates() - Determines checked/indeterminate states for all options
  • handleCheckboxChange() - Manages cascading checkbox selections
  • getAllDescendants() - Recursively finds all child options
  • renderCheckbox() - Renders individual checkboxes with proper indentation

Accessibility

  • Proper aria-checked states (true, false, mixed)
  • Semantic list structure with ul/li elements
  • Note: still need to add legend and fieldset but going to do that as a follow up

Key Behaviors

  • Parent Selection: Checking a parent checkbox selects all descendants
  • Child Selection: Individual child selections update parent state to indeterminate
  • Full Selection: When all children are selected, parent becomes fully checked
  • Deselection: Unchecking a parent deselects all descendants
  • Default Values: Parent values in defaults automatically expand to include all children
  • Visual Hierarchy: Nested options are visually indented by 24px per level

PR Checklist

  • Related to designs:
  • Related to JIRA ticket: GM-1217
  • 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

ConnectedForm

  1. Go to ConnectedForm story
  2. See the nested checkboxes in the playground story
  3. Confirm react, typescript, and backend (and all children descendants) are checked by default
  4. Confirm you are able to deselect and default selected child like node
  5. Confirm you are able to deselect a default selected checkbox like react
  6. Check any parent
  7. Verify all children are selected
  8. Uncheck the parent
  9. Verify all children are deselected
  10. Check individual children
  11. Verify parent shows indeterminate state
  12. Check all children individually
  13. Verify parent becomes fully checked

GridForm

  1. Go to the GridForm story
  2. See the nested checkboxes in the playground story
  3. Confirm react, vue, and backend (and all children descendants) are checked by default
  4. Confirm you are able to deselect and default selected child like node
  5. Confirm you are able to deselect a default selected checkbox like react
  6. Check any parent
  7. Verify all children are selected
  8. Uncheck the parent
  9. Verify all children are deselected
  10. Check individual children
  11. Verify parent shows indeterminate state
  12. Check all children individually
  13. Verify parent becomes fully checked

Accessibility Testing

Use a screen reader (VoiceOver on Mac, NVDA on Windows) to verify:

  1. Parent checkboxes announce as "mixed" when indeterminate
  2. Proper checkbox labels are read
  3. List structure is announced correctly

Test keyboard navigation:

  1. Tab through all checkboxes
  2. Space bar activates checkboxes
  3. Verify focus management

Edge Cases

You can update the playground examples to test the following

  1. Empty Options: Test with options: []
  2. Single Level: Test with no nested children
  3. Deep Nesting: Test with 3+ levels of nesting
  4. Disabled States: Test individual and global disabled states
  5. Numeric Values: Test with numeric option values
  6. Tight Spacing: Test passing spacing: 'tight' and see the spacing more compact

PR Links and Envs

Repository PR Link
Monolith Monolith PR
Mono Mono PR
Author Author PR

Copy link

nx-cloud bot commented Sep 8, 2025

View your CI Pipeline Execution ↗ for commit 90cb56a

Command Status Duration Result
nx run-many --target=verify --parallel=3 --all ✅ Succeeded <1s View ↗
nx run-many --target=build --all ✅ Succeeded 17s View ↗

☁️ Nx Cloud last updated this comment at 2025-10-16 14:44:18 UTC

Copy link
Contributor

@dreamwasp dreamwasp left a comment

Choose a reason for hiding this comment

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

looks good so far! just have some nits about duped logic and comments. everything is working well minus the useConnectedForm default type + i'd love to see some tests

Copy link
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.

Left some thoughts — the functionality's great!!

@aresnik11 aresnik11 changed the title Ajr nested checkboxes feat(GridForm, ConnectedForm): Add nested checkboxes Sep 29, 2025
@aresnik11 aresnik11 marked this pull request as ready for review October 1, 2025 19:00
@aresnik11 aresnik11 requested a review from a team as a code owner October 1, 2025 19:00
Copy link
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.

Functionality's still great! :)
One thing I did notice when trying the edge-cases is that once I got into a nestedCheckbox with 5 layers (4 worked fine) I got a "Maximum call stack exceeded" in SB.
Not sure if this is SB related or not 🤔

Copy link
Contributor

@dreamwasp dreamwasp left a comment

Choose a reason for hiding this comment

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

looks good to me! would like to mess around with the alpha in author because it has some advanced uses of connectedforms but this works with all the edge-cases i could think of

},
size: 4,
},
{
Copy link
Contributor

Choose a reason for hiding this comment

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

may should add a section here on nested checkbox or link the component story. maybe something about the shape of the returned data from the form?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

where do you think this fits best? GridForm doesnt currently have any documentation on the fields available... and then ConnectedForm doesn't have any docs on all the customizations lol

Copy link
Contributor Author

Choose a reason for hiding this comment

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

started completely revamping the GridForm docs while including this and am going to do it as a follow up


export interface ConnectedSelectProps
extends Omit<SelectProps, 'defaultValue' | 'name' | 'validation'>,
extends FieldComponent<SelectProps>,
Copy link
Contributor

Choose a reason for hiding this comment

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

❤️ the DRYing up here

@codecademydev
Copy link
Collaborator

📬Published Alpha Packages:

@codecademy/[email protected]
@codecademy/[email protected]
@codecademy/[email protected]

@codecademydev
Copy link
Collaborator

🚀 Styleguide deploy preview ready!

https://68ee9eece4654ee0fa6e42e0--gamut-preview.netlify.app

Deploy Logs

@codecademydev
Copy link
Collaborator

📬 Published Alpha Packages:

@codecademy/[email protected]
@codecademy/[email protected]
@codecademy/[email protected]

Copy link
Contributor

Copy link
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.

Encountered some VO bug where checking all the children checkboxes visually changes the checkbox but the VO announces the parent as mixed. This happens across all VO tools: VO, NVDA, and JAWS, not sure if this is fixable.

Otherwise, it looks great! well done~

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.

4 participants