Action Bar
The <x-wirekit::action-bar> component creates a floating toolbar that appears at the bottom of the viewport — typically used for bulk actions when one or more items are selected in a list or table. It uses role="group" — a named set of related controls, each reached with Tab — and announces its presence to screen readers via a live region.
Usage
The preview below uses mode="static" so the bar renders inline within the docs preview frame. The default mode="floating" pins the bar to the bottom-center of the viewport via position: fixed — see Layout Modes for the full positioning details and when to choose each.
With Livewire state:
<x-wirekit::action-bar :visible="$selectedCount > 0">
<span class="text-[var(--color-wk-text-muted)]">{{ $selectedCount }} items selected</span>
<x-wirekit::button size="sm" wire:click="archiveSelected">Archive</x-wirekit::button>
<x-wirekit::button size="sm" intent="danger" wire:click="deleteSelected">Delete</x-wirekit::button>
</x-wirekit::action-bar>
With Livewire
The visible prop is typically bound to a Livewire computed property or state. The bar appears when items are selected and disappears when the selection is cleared.
{{-- In your Livewire component --}}
<x-wirekit::action-bar :visible="count($this->selected) > 0">
<span class="text-[length:var(--text-wk-sm)] text-[var(--color-wk-text-muted)]">
{{ count($this->selected) }} selected
</span>
<x-wirekit::button size="sm" wire:click="exportSelected">
Export
</x-wirekit::button>
<x-wirekit::button size="sm" intent="neutral" surface="ghost" wire:click="clearSelection">
Clear
</x-wirekit::button>
<x-wirekit::button size="sm" intent="danger" wire:click="deleteSelected">
Delete
</x-wirekit::button>
</x-wirekit::action-bar>
Custom Content
The action bar accepts any content in its default slot — buttons, text, badges, or any other components:
<x-wirekit::action-bar :visible="$hasUnsavedChanges">
<x-wirekit::icon name="warning" class="text-[var(--color-wk-warning-text)]" />
<span>You have unsaved changes</span>
<x-wirekit::button size="sm" wire:click="save">Save</x-wirekit::button>
<x-wirekit::button size="sm" intent="neutral" surface="ghost" wire:click="discard">Discard</x-wirekit::button>
</x-wirekit::action-bar>
Alpine-Controlled Visibility
You can also control visibility with Alpine instead of server-side Livewire state:
<div x-data="{ selected: [] }">
{{-- Table with checkboxes that populate selected[] --}}
<x-wirekit::action-bar x-show="selected.length > 0" :visible="true">
<span x-text="selected.length + ' items selected'"></span>
<x-wirekit::button size="sm" @click="bulkAction()">Process</x-wirekit::button>
</x-wirekit::action-bar>
</div>
When using Alpine's x-show for visibility, set :visible="true" on the component so the server renders the bar in the DOM. Alpine will then control its display state client-side.
The built-in announcement is server-driven
A live region speaks when its text CHANGES while the region is already on the page. With
:visible="true" the bar's text is there from first paint and Alpine only flips
display, so the bar's own region stays silent and the announcement is yours to make —
write the wording into an aria-live="polite" element of your own when selected.length
crosses zero. Server-driven visibility (:visible="$hasSelection" re-rendered by Livewire)
announces on its own, because the flip is what changes the text.
Layout Modes
The action bar ships in two layout modes, controlled by the mode prop. Both share the same chrome — bordered, elevated, rounded, padded — and only the positioning differs.
mode="floating" (default)
Pinned to the bottom center of the viewport via position: fixed:
position: fixedwithbottomspacing from--padding-wk-y-lg- Horizontally centered via
left: 50%+transform: translateX(-50%) z-indexfrom--z-wk-sticky— sits above page content but below modals and drawers
This is the default mode and the right choice for list pages where the bar should hover over the content while the user scrolls. Visible regardless of scroll position.
mode="static"
Renders inline with surrounding content (inline-flex) — drops the fixed positioning and the viewport-centering transforms, keeps the same visual chrome:
<x-wirekit::action-bar mode="static" :visible="true">
<span>3 selected</span>
<x-wirekit::button size="sm">Archive</x-wirekit::button>
<x-wirekit::button size="sm" intent="danger">Delete</x-wirekit::button>
</x-wirekit::action-bar>
Use this mode when the bar belongs to a card / panel / dashboard rather than a viewport-floating overlay — for example a "selected items" toolbar inside a section, or a contextual bar inside a tab. Composes cleanly with normal flow layouts (flex, grid, document order).
Behavior
- Server-rendered visibility — when
visibleisfalse, the component renders withdisplay: none - Livewire-friendly — the
visibleprop re-evaluates on every Livewire render cycle, so the bar appears/disappears automatically as the selection state changes - Slot-based — the action bar has no opinion about its content; you fill it with buttons, text, or any other components
Props
| Prop | Type | Default | Description |
|---|---|---|---|
visible |
bool |
false |
Whether the action bar is currently visible |
mode |
string |
'floating' |
Layout mode: 'floating' (viewport-pinned, the default) or 'static' (inline) |
scope |
string|null |
null |
Scoped personalization key |
Accessibility
- Container:
role="group"— announces the bar as one named set of related controls aria-label="Bulk actions"— provides an accessible name describing the group's purpose- Live region:
aria-live="polite"announces "Bulk actions available" to screen readers when the server renders the bar visible (see the note under Alpine-Controlled Visibility for the client-driven case) - All buttons inside the bar are natively keyboard-accessible
- Focus ring visible on all interactive elements
- Every string the bar speaks is translated — run
php artisan vendor:publish --tag=wirekit-langto override the wording
Why group and not toolbar
role="toolbar" is a promise about the keyboard: one tab stop for the whole bar, arrow
keys moving between the controls inside it. The action bar binds no keys — it is a layout
wrapper, and its children are ordinary buttons that Tab reaches one by one. role="group"
describes exactly that. If you want the arrow-key model, use
<x-wirekit::toolbar>.
Keyboard Interaction
This component is a layout wrapper. Keyboard interaction is delegated to its children.
Pitfalls
- Don't use action-bar as a permanent UI. It's purpose-built for transient bulk-action contexts (selected rows). For persistent action surfaces use
<x-wirekit::toolbar>.
Design Tokens
| Token | Used for |
|---|---|
--font-wk-sans |
Action-bar font family |
--text-wk-md |
Action-bar font size |
--color-wk-text |
Action-bar text |
--color-wk-bg-elevated |
Action-bar background |
--color-wk-border |
Action-bar border |
--border-wk-width |
Border width |
--radius-wk-xl |
Pill-shaped border radius |
--shadow-wk-lg |
Floating-mode drop shadow |
--gap-wk-md |
Gap between action buttons |
--padding-wk-x-lg / --padding-wk-y-sm / --padding-wk-y-lg |
Container padding |
--z-wk-sticky |
Floating-mode stacking context |
Personalization
Override classes globally via WireKit::personalize():
use Pushery\WireKit\WireKit;
WireKit::personalize('action-bar', [
'base' => 'fixed bottom-4 left-1/2 -translate-x-1/2 z-50 flex items-center gap-4 px-6 py-3 bg-gray-900 text-white rounded-full shadow-2xl',
]);
Further Reading
- MDN:
role="group"— the role the bar carries - WAI-ARIA Toolbar Pattern — the arrow-key model this component deliberately does not implement;
<x-wirekit::toolbar>is the component for it - MDN:
aria-live— live region for visibility announcements