Data & tables
Batch Gesture Tray
Spring floating tray with multi-select batch actions
detent-batch-gesture-tray
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 4
- Wave
- phase-4-motion-controls
- Group
- Data & tables
6.7 KB gzip for the class module · inlines the shared spring
Variants
A local demo of four sample files. Select any row (or use Select all) and the tray rises with the bulk
actions. Every row is a native checkbox, so Space toggles it and Enter works too;
Esc, the close button and a tap outside the tray all clear the selection. Export is
synchronous, Archive takes 600 ms (the button shows a spinner and every action is disabled while it
runs) and Delete is a danger-toned demo. Nothing is uploaded, archived or deleted: the element only
reports detent-selection-change with { ids } and detent-action-complete with
{ actionId }.
No selection yet.
Recorded states
loadingrecorded state; no setterclosedrecorded state; no setterselectedrecorded state; no setter
Usage
Import
import '/components/batch-gesture-tray/define.js';
// or register it yourself
import { DetentBatchGestureTray } from '/components/batch-gesture-tray/batch-gesture-tray.js';
Attributes
No attributes are recorded for this component.
Properties
actionsitemsonActionCompleteonSelectionChangeselectedIds
Slots
No slots are recorded for this component.
Events
detent-selection-change— {}detent-action-complete— {}
Example
Runnable example: site/examples/batch-gesture-tray.ts. The snippet below is generated from the catalogued attributes.
<detent-batch-gesture-tray></detent-batch-gesture-tray>
Property-only values
const element = document.querySelector('detent-batch-gesture-tray');
if (element !== null) {
// items: BatchItem[]
element.items = [];
// actions: BatchAction[]
element.actions = [];
// selectedIds: string[]
element.selectedIds = [];
// onSelectionChange: (ids: string[]) => void
element.onSelectionChange = () => {};
// onActionComplete: (actionId: string) => void
element.onActionComplete = () => {};
}
Source
The pinned upstream source for this row:
src/components/ui/BatchGestureTray.tsxsha256 0835b6e3a337…
Native files
The native module and its artifacts:
src/components/batch-gesture-tray/batch-gesture-tray.tssrc/components/batch-gesture-tray/styles.csssrc/components/batch-gesture-tray/define.tsdocs/components/batch-gesture-tray.mdsite/examples/batch-gesture-tray.tstests/browser/batch-gesture-tray.spec.tsevidence/components/batch-gesture-tray.md
API
Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.
Attributes
No attributes are recorded for this component.
Properties
| Property | Type | Default | Notes |
|---|---|---|---|
actions | BatchAction[] | — | Property-only: assign from script; not accepted as an attribute. |
items | BatchItem[] | — | Property-only: assign from script; not accepted as an attribute. |
onActionComplete | (actionId: string) => void | undefined | Property-only: assign from script; not accepted as an attribute. |
onSelectionChange | (ids: string[]) => void | undefined | Property-only: assign from script; not accepted as an attribute. |
selectedIds | string[] | undefined | Property-only: assign from script; not accepted as an attribute. |
Events
| Event | Upstream prop | Payload type | Notes |
|---|---|---|---|
detent-selection-change | onSelectionChange | (ids: string[]) => void | Composed, bubbles; fires only for a user action. |
detent-action-complete | onActionComplete | (actionId: string) => void | Composed, bubbles; fires only for a user action. |
Slots
No slots are recorded for this component.
CSS customisation
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- items[].icon and actions[].icon are short glyph strings rendered aria-hidden; the row records no slots, so ReactNode icons have no native form.
- Items are native input[type=checkbox] inside a label (upstream used role=checkbox divs with custom key handling); Enter is kept as an extra toggle key.
- The aria-live region moved from the toolbar to a visually hidden role=status count.
- Outside-tap dismissal uses a document pointerdown listener although the pinned source has no outside handler; the row feature list is the authority.
- Escape and outside-tap listeners are per instance, so one outside tap clears every open tray.
What it does
A list of selectable items plus a floating tray that rises as soon as one item is selected and offers bulk actions for that selection.
Upstream behaviour
- Spring slide-up bottom tray appearing automatically when 1 or more items are selected
- Integrated selection counter badge with Select-All / Deselect-All triggers
- Async action loading indicators preventing double-submission
- Dismissal via close button, escape key, or outside tap
Differences from upstream
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- items[].icon and actions[].icon are short glyph strings rendered aria-hidden; the row records no slots, so ReactNode icons have no native form.
- Items are native input[type=checkbox] inside a label (upstream used role=checkbox divs with custom key handling); Enter is kept as an extra toggle key.
- The aria-live region moved from the toolbar to a visually hidden role=status count.
- Outside-tap dismissal uses a document pointerdown listener although the pinned source has no outside handler; the row feature list is the authority.
- Escape and outside-tap listeners are per instance, so one outside tap clears every open tray.