---
title: Action Bar
description: Floating action bar for bulk operations
visibility: guest
draft: false
---

# 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="toolbar"` 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](#layout-modes) for the full positioning details and when to choose each.

:::preview{title="Action Bar (static mode)"}
<x-wirekit::action-bar mode="static" :visible="true">
    3 items selected
    <x-wirekit::button size="sm">Archive</x-wirekit::button>
    <x-wirekit::button size="sm" intent="danger">Delete</x-wirekit::button>
</x-wirekit::action-bar>
:::

With Livewire state:

```blade
<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.

```blade
{{-- 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:

```blade
<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:

```blade
<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>
```

::: tip
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.
:::

## 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: fixed` with `bottom` spacing from `--padding-wk-y-lg`
- Horizontally centered via `left: 50%` + `transform: translateX(-50%)`
- `z-index` from `--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:

```blade
<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 `visible` is `false`, the component renders with `display: none`
- **Livewire-friendly** — the `visible` prop 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="toolbar"` — identifies the element as a toolbar to assistive technology
- `aria-label="Bulk actions"` — provides an accessible name describing the toolbar's purpose
- Live region: `aria-live="polite"` announces "Bulk actions available" to screen readers when the bar becomes visible
- All buttons inside the toolbar are natively keyboard-accessible
- Focus ring visible on all interactive elements

## 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()`:

```php
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

- [WAI-ARIA Toolbar Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/toolbar/) — the authoring pattern this component implements
- [MDN: `role="toolbar"`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/toolbar_role)
- [MDN: `aria-live`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-live) — live region for visibility announcements
