Skip to content
Brok UI

Loading…

No results

Attention Banners

Open source

Why a screen needs a person, most severe first — one alert per cause with the action that owns the fix; renders nothing at all when the list is empty.

Version
v1.0.2
Stability
stable
License
MIT
Related
Alert
Record Header
System Banner

Preview

previews.components.admin-attention-banners.default.blade.php Blade
<div class="w-full">
    <x-ui.admin.attention-banners />
</div>

Installation

terminal
php artisan ui:add admin-attention-banners

Registry contract

php artisan ui:add admin-attention-banners writes only the files below. The CLI validates each file hash before writing and asks before it replaces a local change, unless you pass --force.

  • blade resources/views/components/ui/admin/attention-banners.blade.php
Registry dependencies
alert button
Packages
composer: jml/brok:^0.2

Use with AI

A brief for your coding agent: install command, usage, props, guidance and the rules. Copy it, or open a prompt about this component in an assistant.

admin-attention-banners.md
# Brok UI: Attention Banners (`admin-attention-banners`)

Why a screen needs a person, most severe first — one alert per cause with the action that owns the fix; renders nothing at all when the list is empty.

Brok UI is a Laravel Blade component registry. Installed components are plain Blade files the app owns.

## Install

```bash
php artisan ui:add admin-attention-banners
```

## Usage

```blade
<div class="w-full">
    <x-ui.admin.attention-banners />
</div>
```

## Props

- `banners` (array|null, default `null`) — [['tone' => 'negative'|'attention'|'info'|'positive','title','body' => null,'actionLabel' => null,'actionHref' => null,'id' => null]]. `null` renders a sample set; `[]` renders nothing.
- `heading` (string|null, default `null`) — Accessible name of the region.

## Use when

- Use for important messages that should stay visible long enough to read and act on.
- A record or list has causes a person must act on, each with a screen that fixes it.
- A form was duplicated from another record and must say what was not copied.

## Avoid when

- Do not downgrade important guidance into transient messaging users can miss.
- A single inline field error — use `field`.
- Ambient system status — use `system-banner`.

## Anti-patterns

- Downgrading important outcomes to transient feedback

## Rules

- Use the `<brok:admin-attention-banners>` tag (or `<x-ui.admin-attention-banners>`) in Blade; do not rewrite the component.
- Prefer the documented props and variants over utility-class overrides; when a utility must win, use the `!` important modifier.
- Use semantic design tokens (`bg-primary`, `text-muted-foreground`), never raw colour utilities.
- Keep the `data-slot` attributes; they are the styling and test hooks.

## Links

- Docs: https://brokui.dev/docs/components/admin-attention-banners
- Registry JSON (files, props, contract): https://brokui.dev/r/open/admin-attention-banners.json

Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.

API

manifest knowledge + registry-derived coverage

Props

Props accepted by this component: name, type, default value and description.
Prop Type Default Description
banners array | null null [['tone' => 'negative'|'attention'|'info'|'positive','title','body' => null,'actionLabel' => null,'actionHref' => null,'id' => null]]. `null` renders a sample set; `[]` renders nothing.
heading string | null null Accessible name of the region.

Slots

Default Blade slot only.

Data slots

Stable hooks for CSS overrides and browser tests.

attention-banners

Behavior

  • Sorted here: negative, then attention, then info, then positive; stable within a tone.
  • An empty array renders no wrapper, so callers never guard the include.
  • Declares registry capability flags: a11y, responsive, rtl, darkMode, localized.

Guidance

Persistent message and notification

Keep an important message visible near its context.

Use when

  • Use for important messages that should stay visible long enough to read and act on.
  • A record or list has causes a person must act on, each with a screen that fixes it.
  • A form was duplicated from another record and must say what was not copied.

Avoid when

  • Do not downgrade important guidance into transient messaging users can miss.
  • A single inline field error — use `field`.
  • Ambient system status — use `system-banner`.

Use instead

  • Toast for low-priority confirmation

Anti-patterns

  • Downgrading important outcomes to transient feedback
Anatomy
attention-banners
Theming hooks
attention-banners

Accessibility

WCAG 2.2 AA Keyboard focus-visible RTL-ready Localized labels Dark mode
Keyboard
No component-owned keyboard interaction; native element behavior applies.
Focus
none
  • Each banner is an `alert` primitive; the action is a real link, never a colour cue alone.
  • Semantic HTML and a stable data-slot attribute for styling and scripting hooks.
  • Focus-visible rings use the ring token, so keyboard focus is always visible.
  • Disabled and invalid states are conveyed to assistive tech, not by color alone.
  • Targets WCAG 2.2 AA; verify contrast in light, dark, admin and customer surfaces in the preview.
  • Labels go through __() and layout uses logical properties (ms-*, text-start), so it mirrors under dir="rtl" — flip the preview to RTL to confirm.
  • Dark mode uses the same semantic tokens under the dark class; high contrast follows forced-color system tokens.

Livewire

Safe

Livewire can update this component through forwarded wire:* attributes.

Source

The exact, editable file ui:add writes into your app. Previews render this same code; there are no preview-only components.

resources/views/components/ui/admin/attention-banners.blade.php Blade
{{--
    Attention Banners — why this screen needs a person, most severe first.

    One banner per cause. Each names what is wrong in the operator's words
    and offers the screen that owns the fix, so a banner is a route to the
    work rather than a report about it. A banner without a cause is
    decoration: the component renders nothing at all for a healthy record, and
    the caller never has to guard the include.

    Ordering is decided here, not by the caller: negative before attention
    before info, stable within a tone. A read model can emit its causes in
    whatever order it finds them and the screen still leads with the one
    that costs the most.

    Role gating is the caller's job. A banner whose conclusion is about
    margin is cost data even when it states no figure, so the page filters
    the list before passing it; this component renders what it is given and asks
    no questions about who is reading.

    Generalised from the Noord-C admin's `record/banners.blade.php` (five
    module copies) and the orders list's `operational-alerts.blade.php`.
--}}
@props([
    // null (absent) renders the sample set so the docs preview shows the
    // component; an explicit [] renders nothing, which is the promise above.
    'banners' => null,
    'heading' => null,
])

@php
    // Shapes documented in item.json knowledge.props:
    //   banners: [['tone' => 'negative'|'attention'|'info'|'positive', 'title', 'body' => null, 'actionLabel' => null, 'actionHref' => null, 'id' => null]]
    $banners ??= [
        [
            'tone' => 'attention',
            'title' => __('Payment sync delayed'),
            'body' => __('The payment provider has not confirmed a status for 6 orders in the last 15 minutes. Figures for those orders may be out of date.'),
            'actionLabel' => __('View affected orders'),
            'actionHref' => '#',
        ],
        [
            'tone' => 'negative',
            'title' => __('Stock claim failed'),
            'body' => __('Two lines on this order could not reserve stock. Fulfilment will stall until the warehouse resolves them.'),
            'actionLabel' => __('Open warehouse queue'),
            'actionHref' => '#',
        ],
        [
            'tone' => 'info',
            'title' => __('Duplicated from #1042'),
            'body' => __('Everything was copied except the customer credit, which belongs to the original order.'),
            'actionLabel' => __('Open #1042'),
            'actionHref' => '#',
        ],
    ];

    $severity = ['negative' => 0, 'attention' => 1, 'info' => 2, 'positive' => 3];
    $variants = ['negative' => 'destructive', 'attention' => 'warning', 'info' => 'info', 'positive' => 'success'];

    $banners = collect((array) $banners)
        ->filter(fn ($entry) => is_array($entry))
        ->sortBy(fn (array $banner): int => $severity[$banner['tone'] ?? 'info'] ?? 2, SORT_NUMERIC, false)
        ->values();

    $heading ??= __('Needs attention');
@endphp

@if ($banners->isNotEmpty())
    <section
        data-slot="attention-banners"
        data-surface="admin"
        aria-label="{{ $heading }}"
        {{ $attributes->merge(['class' => 'flex flex-col gap-2']) }}
    >
        @foreach ($banners as $banner)
            @php $tone = $banner['tone'] ?? 'info'; @endphp
            <x-ui.alert
                :variant="$variants[$tone] ?? 'info'"
                :data-tone="$tone"
                :id="$banner['id'] ?? null"
                class="flex flex-wrap items-start justify-between gap-x-6 gap-y-2"
            >
                <div class="min-w-0 flex-1 basis-64">
                    <x-ui.alert.title>{{ $banner['title'] ?? '' }}</x-ui.alert.title>
                    @if (! empty($banner['body']))
                        <x-ui.alert.description class="max-w-prose text-pretty">{{ $banner['body'] }}</x-ui.alert.description>
                    @endif
                </div>

                @if (! empty($banner['actionLabel']))
                    <x-ui.button variant="outline" size="sm" :href="$banner['actionHref'] ?? '#'" class="shrink-0">
                        {{ $banner['actionLabel'] }}
                    </x-ui.button>
                @endif
            </x-ui.alert>
        @endforeach
    </section>
@endif

Ownership & lifecycle

Owner, release state, review evidence and adoption for this item.
Owner
Platform UI (@JoshJML)
Current version
1.0.2
Status
Stable
License
open
Accessibility reviewed
No review date recorded
Last breaking change
No date recorded
Deprecation
Not deprecated
Contract
v6
Foundation
≥ 1.0.0