Selection Slot
Shows your normal tools until something is selected. Then it shows the selection toolbar in the same place. The row keeps its height, so nothing below it moves.
Selection toolbar swap
A button selects sample records and the toolbar becomes the selection. Clear returns focus to the button that opened it.
Table query bar
Select rows to swap the table tools for bulk actions. Below 36rem the actions fold into a menu. Board and List have no row selection, so the tools come back.
| Customer | Status | Total | |
|---|---|---|---|
| Amara Osei | Paid | $1,240.00 | |
| Lukas Brandt | Pending | $86.50 | |
| Priya Natarajan | Refunded | $312.99 | |
| Mateo Alvarez | Paid | $58.00 |
Files toolbar
Selecting files or folders swaps the filters for a toolbar of actions. File-only actions appear when a file is selected. Below 44rem the actions fold into a menu. Trash keeps the filters even with a selection.
- Q3 planningSep 30
- Supplier contract 2026.pdfOct 12
- Harvest yield forecast — greenhouse north and south wings.xlsxOct 15
- Brand photosAug 2
Usage
import { SelectionSlot } from "@tulipfarm/sprout/selection-slot";
<SelectionSlot
active={selected.length > 0}
selection={
<div role="toolbar" aria-label="Selected items" className="flex items-center gap-2">
<p role="status" className="min-w-0 flex-1 truncate">{selected.length} selected</p>
<Button variant="outline" size="sm">Move</Button>
<Button variant="ghost" size="sm" aria-label="Clear selection" onClick={clear}>
Clear
</Button>
</div>
}
>
<FilterBar />
</SelectionSlot>active chooses what shows. children are the tools for no selection, such as search and filters. selectionis the toolbar for selected items. Other props, such asclassName and ref, go to the outerdiv.
There are no variants or sizes. The slot has no padding, border, or color. Its content sets the look, so it fits any toolbar.
Optional selection
const selection = layout === "table" && rows.length > 0
? <BulkRecordActions records={rows} clear={clear} />
: undefined;
<div className="min-w-0 flex-1">
<SelectionSlot active={!!selection} selection={selection}>
<fieldset disabled={editing} aria-label="Table tools">…</fieldset>
</SelectionSlot>
</div>selection can be undefined whileactive is false. Put the slot in a min-w-0 flex-1wrapper when it shares a row with other controls. A disabledfieldset in the tools still works, and so do disabled or busy buttons in the selection.
Fit the width
.selected-wide { display: none; }
@container sprout-selection (width >= 36rem) {
.selected-wide { display: flex; }
.selected-menu { display: none; }
}
/* Tailwind: hidden @xl/sprout-selection:flex */The slot is a size container named sprout-selection. Use it to show buttons when the slot is wide and a "Selected actions" menu when it is narrow. The examples above switch at 36rem for tables and 44rem for files.
Focus
When the selection opens, the slot remembers the focused element. If focus was in the tools, which are now hidden, it moves to the first control in the selection. If focus was somewhere else, such as a row checkbox, it stays there.
When the selection closes and its focused button goes away, focus goes back to the remembered element, if it is still on the page. Clear returns you to the checkbox or button you started from.
Accessibility
The hidden tools stay mounted, so their state survives. They areinert and aria-hidden, so Tab, clicks, and screen readers skip them. Give the selection a role and name, such asrole="toolbar" with aria-label="Selected items", and put the count in role="status" so it is announced. Give an icon-only or short button, such as Clear, anaria-label.
The selection fades in over 180ms. The tools hide at once, so the two never overlap. The fade stops when reduced motion is requested.
Theme tokens
The slot has no color of its own. The fade uses--sprout-motion-normal and --sprout-motion-ease.