Skip to content

fix(Table): Make checkbox selection interactive and fix click handling#17

Open
mattrothenberg wants to merge 5 commits intocloudflare:mainfrom
mattrothenberg:fix/table-checkbox-selection
Open

fix(Table): Make checkbox selection interactive and fix click handling#17
mattrothenberg wants to merge 5 commits intocloudflare:mainfrom
mattrothenberg:fix/table-checkbox-selection

Conversation

@mattrothenberg
Copy link
Contributor

@mattrothenberg mattrothenberg commented Feb 5, 2026

Summary

  • Fix Table checkbox demos on docs site - checkboxes now work interactively
  • Add indeterminate prop support to Table.CheckHead and Table.CheckCell
  • Add default w-10 (40px) width to checkbox cells
  • Expand checkbox hit area using CSS pseudo-element
  • Add dropdown menu to full example's action button
check.mov

Problem

The Table component demos at https://kumo-ui.com/components/table/ had non-functional checkboxes:

  1. "Selected Row" and "Full Example" tables didn't show row highlights when selected
  2. Checkboxes didn't work at all - they were static with no state management

Solution

Component changes (table.tsx)

  • Added indeterminate prop to Table.CheckHead and Table.CheckCell for partial selection state
  • Added w-10 default width to checkbox cells for consistent sizing
  • Used CSS pseudo-element (before:-inset-3) to expand the checkbox hit area without needing wrapper hacks

Demo changes (TableDemo.tsx)

  • Added proper React state management (useState<Set<string>>) to all checkbox demos
  • Wired up onValueChange handlers for interactive selection
  • Added indeterminate state to header checkboxes
  • Removed redundant colgroup width for checkbox column (component handles it now)
  • Added DropdownMenu to the action button with View, Edit, Delete options

Open Question

Is the variant="selected" API on Table.Row weird? Would a boolean make more sense here?

<Table.Row variant={selectedIds.has(row.id) ? "selected" : "default"}>
  <Table.CheckCell checked={selectedIds.has(row.id)} />

Should we consider:

  • A simpler selected boolean prop on Table.Row?
  • Having the row automatically detect selection from its CheckCell child?

Testing

  1. Visit /components/table/ on the docs site
  2. Click checkboxes - they should toggle once per click
  3. Click the header checkbox - should select/deselect all rows
  4. Selected rows should show background highlight
  5. Partially selected tables should show indeterminate (minus) icon in header
  6. Click the three-dots button - dropdown menu should appear

- Add indeterminate prop to Table.CheckHead and Table.CheckCell
- Fix checkbox click handling by removing onClick stopPropagation that
  was interfering with Base UI's internal click handling
- Refactor TableSelectedRowDemo and TableFullDemo with proper React
  state management for interactive row selection
- Header checkbox now shows indeterminate state when some rows selected
- Regenerate component registry
- Wrap checkbox in span with stopPropagation to prevent double-toggle
  when clicking directly on the checkbox
- Add w-10 (40px) default width to TableCheckCell and TableCheckHead
  so checkbox columns are properly sized without needing colgroup
- Add state management to TableWithCheckboxDemo
- Remove redundant colgroup width from TableFullDemo
Add a DropdownMenu to the DotsThree button with View, Edit, and Delete options
Remove hacky span wrapper with stopPropagation. Instead:
- Remove cell onClick handler entirely
- Use CSS pseudo-element (before:-inset-3) to expand checkbox hit area
- Only onCheckedChange handles clicks - no event bubbling issues

This is cleaner and matches TanStack Table's approach.
}}
aria-label={label ?? "Select row"}
disabled={disabled}
className="relative before:absolute before:-inset-3 before:content-['']"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

CSS trick to make the tap target of the checkbox fill the entire surrounding w-10 div.

Copy link

Choose a reason for hiding this comment

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

Super cool :)

@invisal
Copy link

invisal commented Feb 5, 2026

Is the variant="selected" API on Table.Row weird? Currently you have to pass selection state twice:

While it may seem like you’re passing selection state twice, this is a intentional choice to keep the Table component stateless and presentational. By decoupling the visual highlight from the functional checkbox, we provide developers with full control.

Automated syncing (checking the box when the row is "selected") breaks in complex scenarios—specifically when a single row contains multiple independent actions. For example, in a Permissions Matrix, a row shouldn't be "selected" just because one of several capability checkboxes is active:

<Table>
   <Table.Header>
       <Table.Row>
           <Table.Head>Permission</Table.Head>
           <Table.Head>Write</Table.Head>
           <Table.Head>Read</Table.Head>
       </Table.Row>
   </Table.Header>
   <Table.Body>
        <Table.Row>
            <Table.Cell>D1</Table.Cell>
            <Table.CellCheck />
            <Table.CellCheck />
        </Table.Row>
   </Table.Body>
</Table>

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.

2 participants