BulkActionTable

Molecule

Table with **id-keyed** row selection and a bulk-action bar, drawn with the same DOM as kui-react. The server renders the table, the initial selection and the bar; a small idempotent script (`modules/ui/BulkActionTable/scripts/`, inlined once per page) adds select all, select row, the bar and the column sort. Selection is by row id, so sorting does not move it, and the header checkbox only clears the rows on the page. Events on the root replace the React callbacks: `kui:bulk-change` { selected }, `kui:bulk-action` { key, ids }, `kui:bulk-select-all-matching` { count }. An action is disabled outside `minSelected` / `maxSelected` (kui-react takes a function there, which cannot run in the browser). Cells are escaped text; `col.partial` includes a partial instead.

Selection and actions

Preview
1 selected
Companies
Company Country Stage
Northwind Traders DE new
Contoso Ltd GB contacted
Fabrikam NL replied
Adventure Works TR new

Select rows, sort a column, use an action.

Code
<%- include('modules/ui/BulkActionTable', {
  id: 'companies',
  rows: companies,
  rowId: 'companyId',
  selected: selectedIds,
  columns: [
    { key: 'company', header: 'Company', sortable: true },
    { key: 'country', header: 'Country' },
  ],
  actions: [
    { key: 'enrich', label: 'Enrich', icon: 'fa-solid fa-wand-magic-sparkles' },
    { key: 'merge', label: 'Merge', minSelected: 2, disabledReason: 'Select at least two' },
  ],
}) %>
<script>
  document.getElementById('companies').addEventListener('kui:bulk-action', function (e) {
    // e.detail = { key: 'enrich', ids: ['c1', 'c3'] }
  });
</script>

Unselectable rows, and select-all-matching

Preview
1 selected
Company Why not selectable
Northwind Traders
Contoso Ltd Suppressed — replied "stop"
Fabrikam

The suppressed row cannot be selected; the bar offers the wider selection.

Code
<%- include('modules/ui/BulkActionTable', {
  rows: companies,
  rowId: (c) => c.companyId,
  selected: [],
  isRowSelectable: (c) => (c.suppressed ? 'Suppressed' : true),
  totalMatching: total,
  onSelectAllMatching: true, // the button dispatches 'kui:bulk-select-all-matching'
  columns: columns,
  actions: [{ key: 'email', label: 'Email' }],
}) %>

Empty, and custom labels

Preview
Companies
Company
No companies match.
1 chosen
Company
Northwind Traders
Contoso Ltd
Code
<%- include('modules/ui/BulkActionTable', { rows: [], columns: columns, emptyMessage: 'No companies match.' }) %>
<%- include('modules/ui/BulkActionTable', {
  rows: companies, selected: ['c2'], columns: columns,
  labels: { selectRow: 'Pick', selectedCount: '{n} chosen', clear: 'Reset' },
}) %>
Source modules/ui/BulkActionTable.ejs