Skip to content

Table Component: Row Actions & Selection

Tables support interactive items, row actions, expandable sections, and multi-row selection.


Row Actions

Use the rowActions prop to render action menus on each row.

For a clean and consistent UI, group row-level actions into a 3-dots dropdown menu using ActionsDropdown (or ActionsMenu) and ActionItem:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import { FC } from 'react';
import { PencilSimple, Trash } from '@phosphor-icons/react';

import { translate } from '@/i18n';
import { ActionItem } from '@/resource/actions/ActionItem';
import { ActionsDropdown } from '@/table/ActionsDropdown';

interface RowActionsProps {
  row: MyRowType;
  refetch: () => void;
}

export const RowActions: FC<RowActionsProps> = ({ row, refetch }) => {
  const onDelete = () => handleDelete(row).then(refetch);

  // Return null if no actions are available
  if (row.status === 'completed') {
    return null;
  }

  return (
    <ActionsDropdown>
      <ActionItem
        title={translate('Edit')}
        action={() => handleEdit(row)}
        iconNode={<PencilSimple weight="bold" />}
      />
      <ActionItem
        title={translate('Delete')}
        action={onDelete}
        iconNode={<Trash weight="bold" />}
        className="text-danger"
        iconColor="danger"
      />
    </ActionsDropdown>
  );
};

// Usage inside Table:
<Table
  {...tableProps}
  columns={columns}
  rowActions={({ row }) => <RowActions row={row} refetch={tableProps.fetch} />}
/>;

ActionItem Properties

Property Type Description
title string Action label text.
action () => void Click handler callback.
iconNode ReactNode Icon element (use Phosphor icons with weight="bold").
disabled boolean Disables the menu item.
className string Custom CSS class string (e.g. 'text-danger').
iconColor string Visual variant color theme (e.g. 'danger', 'success').

2. Inline Row Action Buttons

For simple tables with very few actions, you can render buttons directly in the row cells:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import { BaseButton } from 'waldur-ui';

const RowActions = ({ row }) => (
  <div className="d-flex gap-2">
    <BaseButton
      onClick={() => handleEdit(row)}
      label={translate('Edit')}
      iconNode={<PencilSimple />}
      variant="tertiary"
      size="sm"
    />
  </div>
);

<Table {...tableProps} columns={columns} rowActions={RowActions} />;

Expandable Rows

Expandable rows show extra details without navigating away.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const ExpandableRowContent = ({ row }) => (
  <div className="p-4">
    <h5>{row.name}</h5>
    <p>Description: {row.description}</p>
  </div>
);

<Table
  {...tableProps}
  columns={columns}
  expandableRow={ExpandableRowContent}
/>;

The caret in the first visible column is a real button: it takes keyboard focus, exposes aria-expanded, controls the details cell (aria-controls) while it is open, and is named "Expand"/"Collapse" plus that cell's text ("Expand Web server"). Make the first visible column one that identifies the row, such as its name. Clicking anywhere else on the row still toggles it.

Conditional Expandability (isRowExpandable)

By default, all rows display carets if expandableRow is present. Disable card expansion for specific rows using isRowExpandable:

1
2
3
4
5
6
<Table
  {...tableProps}
  columns={columns}
  expandableRow={ExpandableRowContent}
  isRowExpandable={(row) => row.has_details} // Returns true or false
/>

Bulk Selection and Actions

Tables support row selection and bulk batch actions in the toolbar.

  1. Set enableMultiSelect to render selection checkboxes on each row.
  2. Pass a component to multiSelectActions to render bulk operations on the selected items. It receives the selected rows and refetch callback.
  3. For destructive actions, use the RemovalActionButton to prompt users with a confirmation panel before execution.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { RemovalActionButton } from '@/table/RemovalActionButton';
import { useManagedMutation } from '@/modal/useManagedMutation';

const BulkDeleteButton = ({ rows, refetch }) => {
  const { mutate, isPending } = useManagedMutation({
    mutationFn: () => deleteMultipleItems(rows.map((r) => r.uuid)),
    successMessage: translate('Selected items deleted.'),
    refetch,
    confirmation: {
      title: translate('Delete selected items'),
      body: translate('Are you sure you want to delete {count} items?', {
        count: rows.length,
      }),
    },
  });

  return (
    <RemovalActionButton
      title={translate('Delete')}
      action={mutate}
      disabled={isPending}
    />
  );
};

// Usage in Table:
<Table
  {...tableProps}
  columns={columns}
  enableMultiSelect
  multiSelectActions={BulkDeleteButton}
/>;