Bulk action bar
Playground
TSX
'use client';
import { useRef, useState } from 'react';
import { BulkActionBar, Button, Checkbox } from '@mbsw/ui';
export default function Demo() {
const [items, setItems] = useState([
{ id: 1, label: "Item 1", completed: false },
{ id: 2, label: "Item 2", completed: false },
{ id: 3, label: "Item 3", completed: false },
]);
const [selected, setSelected] = useState([1, 2, 3]);
const list = useRef<HTMLUListElement>(null);
const bar = useRef<HTMLDivElement>(null);
const clear = () => {
// This list survives even when archiving removes every selected item.
if (bar.current?.contains(document.activeElement)) list.current?.focus();
setSelected([]);
};
return (
<>
<ul
ref={list}
tabIndex={-1}
aria-label={"Item list"}
style={{
display: 'grid',
gap: 16,
listStyle: 'none',
padding: 0,
margin: 0,
}}
>
{items.length === 0 && <li>{"No items."}</li>}
{items.map((item) => (
<li key={item.id}>
<label style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<Checkbox
checked={selected.includes(item.id)}
onCheckedChange={(checked) =>
setSelected((current) =>
checked === true
? [...current, item.id]
: current.filter((id) => id !== item.id),
)
}
/>
<span
style={{
textDecoration: item.completed ? 'line-through' : undefined,
}}
>
{item.label}
{item.completed ? " (Completed)" : ''}
</span>
</label>
</li>
))}
</ul>
{selected.length > 0 && (
<BulkActionBar
ref={bar}
style={{ maxWidth: 'calc(100% - 32px)' }}
selectionLabel={"{count} selected".replace(
'{count}',
String(selected.length),
)}
clearAction={
<Button
size="sm"
variant="outline"
tone="secondary"
onClick={clear}
>
{"Clear selection"}
</Button>
}
actions={
<>
<Button
size="sm"
variant="solid"
tone="secondary"
onClick={() => {
setItems((current) =>
current.filter((item) => !selected.includes(item.id)),
);
clear();
}}
>
{"Archive"}
</Button>
<Button
size="sm"
variant="solid"
tone="primary"
onClick={() => {
setItems((current) =>
current.map((item) =>
selected.includes(item.id)
? { ...item, completed: true }
: item,
),
);
clear();
}}
>
{"Complete"}
</Button>
</>
}
/>
)}
</>
);
}
Usage
Pass the selection count and add action and clear-selection slots. Your app manages selection and updates the data.
TSX
'use client';
import { useRef, useState } from 'react';
import { BulkActionBar, Button, Checkbox } from '@mbsw/ui';
export default function Example({ onComplete }: { onComplete: () => void }) {
const [selected, setSelected] = useState(true);
const checkbox = useRef<HTMLButtonElement>(null);
const bar = useRef<HTMLDivElement>(null);
const clear = () => {
if (bar.current?.contains(document.activeElement))
checkbox.current?.focus();
setSelected(false);
};
return (
<>
<label>
<Checkbox
ref={checkbox}
checked={selected}
onCheckedChange={(value) => setSelected(value === true)}
/>{' '}
{"Item 1"}
</label>
{selected && (
<BulkActionBar
ref={bar}
selectionLabel={"1 selected"}
actions={
<Button
size="sm"
onClick={() => {
clear();
onComplete();
}}
>
{"Complete"}
</Button>
}
clearAction={
<Button size="sm" onClick={clear}>
{"Clear selection"}
</Button>
}
/>
)}
</>
);
}
The Playground Code tab includes the full example with your current settings. See Installation for the CSS imports.