ActionBar
Floating toolbar of bulk actions for the current selection in a collection
The <ActionBar> is a floating toolbar of bulk actions for the items currently selected in a collection. It shows how many items are selected and offers actions that apply to all of them at once.
Reach for it whenever a list or <Table> lets people pick several rows and then act on them together, such as deleting, exporting, or reassigning many records in one step instead of repeating the same action row by row. The Bulk Actions pattern covers the full flow around the bar, from selection scope to confirming destructive actions and reporting partial failures.
Anatomy
- Selection count: States how many items the actions will affect, so the user knows the scope before pressing anything. It reads
All items selectedwhen the collection's select-all is used. - Clear button: Dismisses the bar and clears the selection. Rendered only when a clear handler is available.
- Toolbar: Groups the actions into a single row.
- Action: Each action is a plain
<Button>that runs one operation across the whole selection. The bar adapts it to the toolbar look automatically.
Appearance
The appearance of a component can be customized using the variant and size props. These props adjust the visual style and dimensions of the component, available values are based on the active theme.
| Property | Type | Description |
|---|---|---|
variant | - | The available variants of this component. |
size | - | The available sizes of this component. |
Usage
Keep the bar to a few high-value actions, the ones people reach for again and again on a multi-selection. Name each one with a verb so its effect is obvious, and place a destructive action such as delete last so the safer choices come first. When a selection carries more actions than fit comfortably, move the long tail into an <ActionMenu> rather than crowding the bar.
Do
Use <ActionBar> for actions that apply to the current multi-selection in
a collection, and let it appear only while something is selected.
Don't
Don't use it as a permanent toolbar or for actions on a single row. Reach
for a <ButtonGroup> for per-row or
surface actions, or a single <Button> for
one action.
Bulk actions in a table
The most common home for an <ActionBar> is a <Table> with selectionMode="multiple". Pass the bar through the Table's actionBar prop, and the Table tracks the selection, shows and hides the bar, and reserves space at the bottom so the last row stays reachable while the bar floats above it.
Name | Email | Role | |
|---|---|---|---|
Hans Müller hans@example.de | hans@example.de | Owner | |
Fritz Schneider fritz@example.de | fritz@example.de | Editor | |
Klaus Becker klaus@example.de | klaus@example.de | Viewer | |
Helga Fischer helga@example.de | helga@example.de | Editor | |
Ursula Weber ursula@example.de | ursula@example.de | Viewer | |
Dieter Koch dieter@example.de | dieter@example.de | Editor |
import { ActionBar, Badge, Button, Scrollable, Stack, Table, Text,} from '@marigold/components';import { Copy, Pencil, Trash2 } from '@marigold/icons';const members = [ { id: '1', name: 'Hans Müller', email: 'hans@example.de', role: 'Owner' }, { id: '2', name: 'Fritz Schneider', email: 'fritz@example.de', role: 'Editor', }, { id: '3', name: 'Klaus Becker', email: 'klaus@example.de', role: 'Viewer' }, { id: '4', name: 'Helga Fischer', email: 'helga@example.de', role: 'Editor' }, { id: '5', name: 'Ursula Weber', email: 'ursula@example.de', role: 'Viewer' }, { id: '6', name: 'Dieter Koch', email: 'dieter@example.de', role: 'Editor' },];export default () => ( <Scrollable height="320px"> <Table aria-label="Team members" selectionMode="multiple" defaultSelectedKeys={new Set(['2', '3'])} actionBar={() => ( <ActionBar> <Button onPress={() => alert('Edit')}> <Pencil /> Edit </Button> <Button onPress={() => alert('Copy')}> <Copy /> Copy </Button> <Button onPress={() => alert('Delete')}> <Trash2 /> Delete </Button> </ActionBar> )} > <Table.Header sticky> <Table.Column rowHeader>Name</Table.Column> <Table.Column>Email</Table.Column> <Table.Column>Role</Table.Column> </Table.Header> <Table.Body> {members.map(member => ( <Table.Row key={member.id} id={member.id}> <Table.Cell> <Stack space="0.5"> <Text weight="medium">{member.name}</Text> <Text size="xs" color="secondary"> {member.email} </Text> </Stack> </Table.Cell> <Table.Cell>{member.email}</Table.Cell> <Table.Cell> <Badge>{member.role}</Badge> </Table.Cell> </Table.Row> ))} </Table.Body> </Table> </Scrollable>);Inside the render prop you write only the actions; the selection count and the clear button are filled in for you. The bar stays pinned to the bottom of the scroll area as the user works down a long list.
Acting on a full selection
When the user toggles the Table's select-all checkbox, the selection becomes
the value 'all' and the bar reads All items selected. The actionBar
render prop receives this value, so an action can apply to the entire result
set, including rows that aren't loaded yet, by fetching the full set rather
than the keys currently on screen. Before acting beyond the visible rows, read
the selection scope guidance in the
Bulk Actions pattern, which recommends keeping the selection bounded to what
the user can see.
Bulk editing in a drawer
Some bulk actions need a few inputs before they can run, such as moving many events to a new date and venue at once. Compose a <Button> inside a <Drawer.Trigger> so pressing the action opens a drawer with a small form, and apply the changes across the selection on submit.
Event | Date | Venue | Status | |
|---|---|---|---|---|
Spring Gala | Apr 15, 2025 | Freiburg | Confirmed | |
Jazz Night | May 2, 2025 | Berlin | Confirmed | |
Open Air Theater | Jun 10, 2025 | Hamburg | On Sale | |
Summer Festival | Jul 22, 2025 | Berlin | Confirmed |
import { ActionBar, Badge, Button, Checkbox, DatePicker, Drawer, Select, Stack, Table, Text,} from '@marigold/components';import { Pencil } from '@marigold/icons';const events = [ { id: '1', name: 'Spring Gala', date: 'Apr 15, 2025', venue: 'Freiburg', status: 'Confirmed', }, { id: '2', name: 'Jazz Night', date: 'May 2, 2025', venue: 'Berlin', status: 'Confirmed', }, { id: '3', name: 'Open Air Theater', date: 'Jun 10, 2025', venue: 'Hamburg', status: 'On Sale', }, { id: '4', name: 'Summer Festival', date: 'Jul 22, 2025', venue: 'Berlin', status: 'Confirmed', },];export default () => ( <Table aria-label="Events" selectionMode="multiple" defaultSelectedKeys={new Set(['1', '2', '3'])} actionBar={() => ( <ActionBar> <Drawer.Trigger> <Button> <Pencil /> Edit </Button> <Drawer size="medium"> <Drawer.Title>Edit selected events</Drawer.Title> <Drawer.Content> <Stack space="regular"> <Text> Changes apply to every selected event. Fields you leave empty stay unchanged. </Text> <DatePicker label="Event date" /> <Select label="Venue" placeholder="Choose a venue"> <Select.Option id="freiburg">Freiburg</Select.Option> <Select.Option id="berlin">Berlin</Select.Option> <Select.Option id="hamburg">Hamburg</Select.Option> <Select.Option id="online">Online</Select.Option> </Select> <Checkbox label="Notify attendees of changes" /> </Stack> </Drawer.Content> <Drawer.Actions> <Button slot="close">Cancel</Button> <Button slot="close" variant="primary"> Apply changes </Button> </Drawer.Actions> </Drawer> </Drawer.Trigger> </ActionBar> )} > <Table.Header> <Table.Column rowHeader>Event</Table.Column> <Table.Column>Date</Table.Column> <Table.Column>Venue</Table.Column> <Table.Column>Status</Table.Column> </Table.Header> <Table.Body> {events.map(event => ( <Table.Row key={event.id} id={event.id}> <Table.Cell>{event.name}</Table.Cell> <Table.Cell>{event.date}</Table.Cell> <Table.Cell>{event.venue}</Table.Cell> <Table.Cell> <Badge>{event.status}</Badge> </Table.Cell> </Table.Row> ))} </Table.Body> </Table>);Keep the form short and make it clear that it edits many records at once. A common pattern is to apply only the fields the user fills in and leave the rest of each record untouched.
Outside a table
A <Table> is not required. When you own the selection state yourself, on a gallery, a card grid, or any custom collection, drive the bar directly: pass selectedItemCount so it knows when to appear and what to show, and onClearSelection to reset your selection when the user dismisses it.
import { useState } from 'react';import { ActionBar, Button, Checkbox, CheckboxGroup, Stack,} from '@marigold/components';import { Download, Trash2 } from '@marigold/icons';const files = [ { id: 'report-q1', label: 'Report Q1.pdf' }, { id: 'report-q2', label: 'Report Q2.pdf' }, { id: 'budget', label: 'Budget.xlsx' }, { id: 'notes', label: 'Meeting notes.docx' },];export default () => { const [selected, setSelected] = useState<string[]>(['report-q1']); return ( <Stack space={8}> <CheckboxGroup label="Files" value={selected} onChange={setSelected}> {files.map(file => ( <Checkbox key={file.id} value={file.id} label={file.label} /> ))} </CheckboxGroup> <ActionBar selectedItemCount={selected.length} onClearSelection={() => setSelected([])} > <Button onPress={() => alert('Download')}> <Download /> Download </Button> <Button onPress={() => alert('Delete')}> <Trash2 /> Delete </Button> </ActionBar> </Stack> );};For a collection that manages its own selection wiring the way <Table> does, the useActionBar hook returns the selection handlers, the measured bar height, and the overlay to render alongside the collection.
Accessibility
The <ActionBar> handles the behaviour that bulk-selection patterns are expected to have:
- The actions sit in a toolbar with a localized
Bulk Actionslabel, and the clear button carries its own label, so the bar's purpose is announced. - When the bar appears, screen readers announce that actions are available, without focus jumping away from the collection.
- Pressing Escape clears the selection and dismisses the bar, and focus returns to where it was when the bar closes.
Give every icon-only action a text label as well, either visible next to the icon or through an aria-label, so each action is announced clearly.
Props
ActionBar
Prop
Type
Actions
Actions are plain <Button> elements. Place them directly inside the bar and it cascades the toolbar look (a ghost variant at the default size); a local variant or size on a button still wins. For an icon-only action, set size="icon" and give it an aria-label.
<ActionBar selectedItemCount={3} onClearSelection={clear}>
<Button onPress={edit}>
<Pencil /> Edit
</Button>
<Button size="icon" aria-label="Delete" onPress={del}>
<Trash2 />
</Button>
</ActionBar>useActionBar
Prop
Type
Alternative components
ButtonGroup: Use for a cluster of related actions on a single row or surface, rather than on a selection.
ActionMenu: Use the menu pattern when a selection carries more actions than fit comfortably in the bar.
Button: Use for a single standalone action that doesn't depend on a selection.