MiHCM
primitives/@mihcm/ui·v0.21.0·stable

CheckboxGrid

Multi-select grid with summary, view tabs (All / Selected / Unselected), bulk select-all/clear, filter, and responsive grid. Web only.

Use cases

  • Selecting many items from a long, flat list — designations, job categories, payroll schemes, modules.
  • Any flow where the user needs to scan "what's on" vs "what's off", filter the list, and bulk-toggle.

When NOT to use

  • For a small fixed number of toggles → multiple Switch rows.
  • For a transfer between two pools (assigned ↔ unassigned) → use TransferList.
  • For a single binary choice → use Checkbox.

Platform support

Web: multi-column grid with view tabs (All/Selected/Unselected). Native: single-column FlatList with touch-friendly checkbox rows. View tabs are omitted; filter, select-all, and clear are retained. The columns prop is accepted but ignored on native.

Anatomy

┌────────────────────────────────────────────────────────┐
│ 3 selected · 9 remaining   [All|Selected|Unselected]  │ ← summary bar
│                            [Select All] [Clear]       │
├────────────────────────────────────────────────────────┤
│ [🔍 Filter items…]                                     │ ← search
├────────────────────────────────────────────────────────┤
│ ☑ Engineering    ☑ Product    ☐ Design                │ ← grid
│ ☑ Marketing      ☐ Sales      ☐ Support               │
│ ☐ Finance        ☐ Ops        ☐ HR                    │
└────────────────────────────────────────────────────────┘

Columns

SettingMobileTabletDesktop
columns={1}111
columns={2}122
columns={3} (default)123

Controlled state

selected is a Record<string, boolean>. Missing keys count as false:

const [selected, setSelected] = useState<Record<string, boolean>>({});
 
<CheckboxGrid
  items={['A', 'B', 'C']}
  selected={selected}
  onSelectedChange={setSelected}
/>

The component never mutates your state — onSelectedChange always receives a new object.

Scroll containment

The grid scrolls inside its own bounded region (maxHeight={240} default). For very long lists (60+ items) the search filter does the heavy lifting — bump maxHeight only when there's no good filter axis.

Responsive and customization props

  • layout="auto" creates responsive cards with auto-fit, useful when the same grid must work from mobile to desktop.
  • layout="list" forces one column for dense review screens.
  • density="compact" reduces row height for administrative permission matrices.
  • showToolbar={false} hides count tabs and bulk actions when the grid is embedded inside a larger form.
  • emptyState and getItemClassName let consumers render domain-specific empty copy and tokenized item styling.

Composition

  • Use columns to control grid density. 2 columns is default; 3 works for short labels.
  • Pair with a SectionHeader above the grid for context.
  • selected is a Record<string, boolean> — missing keys count as false.
  • Checkbox — individual checkbox for single boolean fields.
  • TransferList — dual-list picker with move-between semantics.
  • RadioGroup — single selection from a list.