Skip to content
Brok UI

Loading…

No results

Status

Open source

Animated status dots — a person's presence and a system or service's state.

Version
v1.4.2
Stability
stable
License
MIT
Related
Alert
Notification Badge
Status Select

Status — A compact status dot with an optional label and ping/pulse motion. Presence (online, offline, busy, away, neutral) and system (active, fixing, down, idle) vocabularies share one dot.

Preview

Online
Variant
Size
previews.components.status.default.blade.php Blade
{{-- One presence dot; the playground's variant and size controls drive it. --}}
<x-ui.status variant="online" label="{{ __('Online') }}" :pulse="true" />

Variant options

Online Current
Busy Current
Away Current
Offline Current
Neutral Current
Active Current
Fixing Current
Down Current
Idle Current

Size options

Sm Current
Md Current
Lg Current

Installation

terminal
php artisan ui:add status

Registry contract

php artisan ui:add status 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/status.blade.php
Registry dependencies
None — installs on its own.
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.

status.md
# Brok UI: Status (`status`)

A compact status dot with an optional label and ping/pulse motion. Presence (online, offline, busy, away, neutral) and system (active, fixing, down, idle) vocabularies share one dot.

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

## Install

```bash
php artisan ui:add status
```

## Usage

```blade
{{-- One presence dot; the playground's variant and size controls drive it. --}}
<x-ui.status variant="online" label="{{ __('Online') }}" :pulse="true" />
```

## Props

- `variant` (online|busy|away|offline|neutral, default `online`) — Presence (online, busy, away, offline, neutral) or system (active, fixing, down, idle) state; unknown values fall back to neutral.
- `label` (mixed|null, default `null`) — Visible label text; when omitted, the variant name is announced to screen readers only.
- `pulse` (mixed|null, default `null`) — Motion override: true or 'ping' echoes a ring outward, 'pulse' breathes the dot, false stays still; unset lets the variant decide (active pings, fixing pulses).
- `size` (md|sm|lg, default `md`) — Dot and text size: sm, md, or lg.
- `appearance` (string, default `dot`) — dot renders a plain dot and label; pill renders a soft tinted chip with the dot inside.

## Use when

- Use to show state, status, notification, or lightweight social feedback near the relevant object.
- Showing a presence or system state (online, busy, away, offline, active, fixing, down, idle) as a compact dot with an optional label.
- Wanting a pill appearance for a table cell or card header instead of a bare dot and label.

## Avoid when

- Do not overload small status elements with explanations that should remain visible in text.
- Announcing a one-off outcome message rather than an ongoing state; use alert or a toast instead.
- Needing a numeric count on a trigger corner; use notification-badge instead.

## Anti-patterns

- Using color or icon alone to communicate state

## Rules

- Use the `<brok:status>` tag (or `<x-ui.status>`) 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/status
- Registry JSON (files, props, contract): https://brokui.dev/r/open/status.json

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

Examples

states.blade.php Blade
<div class="flex flex-col gap-6">
    {{-- Pill appearance: a soft chip with the dot inside --}}
    <div class="flex flex-wrap items-center gap-3">
        <x-ui.status appearance="pill" variant="online" label="{{ __('Online') }}" :pulse="true" />
        <x-ui.status appearance="pill" variant="busy" label="{{ __('In a meeting') }}" />
        <x-ui.status appearance="pill" variant="away" label="{{ __('Away') }}" />
        <x-ui.status appearance="pill" variant="offline" label="{{ __('Offline') }}" />
    </div>

    {{-- Pulse on vs off --}}
    <div class="flex flex-wrap items-center gap-6">
        <x-ui.status variant="online" label="{{ __('Live') }}" :pulse="true" />
        <x-ui.status variant="busy" label="{{ __('Recording') }}" :pulse="true" />
    </div>

    {{-- Sizes --}}
    <div class="flex flex-wrap items-center gap-6">
        <x-ui.status variant="online" label="{{ __('Small') }}"  size="sm" />
        <x-ui.status variant="online" label="{{ __('Medium') }}" size="md" />
        <x-ui.status variant="online" label="{{ __('Large') }}"  size="lg" />
    </div>

    {{-- No label (sr-only fallback), e.g. on an avatar --}}
    <div class="flex flex-wrap items-center gap-4">
        <x-ui.status variant="online" />
        <x-ui.status variant="busy" />
        <x-ui.status variant="away" />
        <x-ui.status variant="offline" />
    </div>
</div>
system.blade.php Blade
{{-- System vocabulary (the former status-indicator): active pings, fixing
     pulses, down and idle stay still. --}}
<div class="flex flex-col gap-3">
    <x-ui.status variant="active" size="lg" label="{{ __('All systems operational') }}" />
    <x-ui.status variant="fixing" size="lg" label="{{ __('Degraded — recovering') }}" />
    <x-ui.status variant="down" size="lg" label="{{ __('Outage') }}" />
    <x-ui.status variant="idle" size="lg" label="{{ __('Idle') }}" />
</div>
variants.blade.php Blade
<div class="flex flex-wrap items-center gap-6">
    <x-ui.status variant="online"  label="{{ __('Online') }}" :pulse="true" />
    <x-ui.status variant="busy"    label="{{ __('Busy') }}" />
    <x-ui.status variant="away"    label="{{ __('Away') }}" />
    <x-ui.status variant="offline" label="{{ __('Offline') }}" />
    <x-ui.status variant="neutral" label="{{ __('Unknown') }}" />
</div>

API

manifest knowledge + registry-derived coverage

Props

Props accepted by this component: name, type, default value and description.
Prop Type Default Description
variant online | busy | away | offline | neutral online Presence (online, busy, away, offline, neutral) or system (active, fixing, down, idle) state; unknown values fall back to neutral.
label mixed | null null Visible label text; when omitted, the variant name is announced to screen readers only.
pulse mixed | null null Motion override: true or 'ping' echoes a ring outward, 'pulse' breathes the dot, false stays still; unset lets the variant decide (active pings, fixing pulses).
size md | sm | lg md Dot and text size: sm, md, or lg.
appearance string dot dot renders a plain dot and label; pill renders a soft tinted chip with the dot inside.

Slots

  • default — Unused; the component has no visible default slot content.

Data slots

Stable hooks for CSS overrides and browser tests.

status-dot status-dot-ping status-label {{ $slotName }}

Behavior

  • Unless pulse is set explicitly, motion follows the variant: active pings, fixing pulses, every other variant stays still.
  • status-indicator reuses this component under its own data-slot name by passing a data-slot attribute.
  • Exposes status text and an optional token-driven pulse.
  • Declares registry capability flags: a11y, responsive, rtl, darkMode, localized.

Guidance

Status and lightweight feedback

Communicate concise object or system state.

Use when

  • Use to show state, status, notification, or lightweight social feedback near the relevant object.
  • Showing a presence or system state (online, busy, away, offline, active, fixing, down, idle) as a compact dot with an optional label.
  • Wanting a pill appearance for a table cell or card header instead of a bare dot and label.

Avoid when

  • Do not overload small status elements with explanations that should remain visible in text.
  • Announcing a one-off outcome message rather than an ongoing state; use alert or a toast instead.
  • Needing a numeric count on a trigger corner; use notification-badge instead.

Use instead

  • Persistent explanatory text

Anti-patterns

  • Using color or icon alone to communicate state
Anatomy
root status-dot-ping status-dot status-label
Theming hooks
status

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
  • The root carries role="status"; when no visible label is set, the variant name is still announced via an sr-only span.
  • The ping and pulse motion layers are purely decorative and marked aria-hidden.
  • 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/status.blade.php Blade
@props([
    // Presence: online | busy | away | offline | neutral.
    // System:   active | fixing | down | idle.
    'variant' => 'online',
    'label'   => null,
    // Motion on the dot: true|'ping' echoes a ring outward, 'pulse' breathes
    // the dot itself, false is still. Unset, the variant decides — active
    // pings and fixing pulses; every other variant is still.
    'pulse'   => null,
    'size'    => 'md',
    // dot (default): a dot and a plain label. pill: a soft tinted chip with the
    // dot inside — for a table cell or a card header.
    'appearance' => 'dot',
])

@php
    $styles = require base_path(config('ui.component_path', 'resources/views/components/ui').'/_styles.php');
    $variant = $styles['normalizeVariant']($variant);
    $variant = array_key_exists($variant, $styles['status']['variants']) ? $variant : 'neutral';
    $size = in_array($size, ['sm', 'md', 'lg'], true) ? $size : 'md';
    $appearance = $appearance === 'pill' ? 'pill' : 'dot';
    $status = $styles['status'];
    $motion = match (true) {
        $pulse === null => $status['motion'][$variant] ?? false,
        $pulse === true || $pulse === 'ping' => 'ping',
        $pulse === 'pulse' => 'pulse',
        default => false,
    };
    // status-indicator renders this component under its own name; the
    // browser keeps only the first of two identical attributes, so read the
    // override out of the bag and print exactly one.
    $slotName = (string) ($attributes->get('data-slot') ?: 'status');

    $dotColour = $status['variants'][$variant];
    $sizeStyles = $status['sizes'][$size];
    $dotSize = $sizeStyles['dot'];
    // A hollow (offline) dot has no fill for the ping to echo; it pulses the ring colour.
    $pingColour = $variant === 'offline' ? 'bg-muted-foreground/60' : $dotColour;

    $rootClasses = $appearance === 'pill'
        ? 'inline-flex items-center gap-2 rounded-full font-medium '.$status['pills'][$variant].' '.$sizeStyles['pill']
        : $status['base'];
@endphp

<span
    data-slot="{{ $slotName }}"
    data-variant="{{ $variant }}"
    data-appearance="{{ $appearance }}"
    @if ($motion) data-motion="{{ $motion }}" @endif
    role="status"
    {{ $attributes->except('data-slot')->merge(['class' => $rootClasses]) }}
>
    {{-- Dot wrapper (relative so the ping layer can be absolute) --}}
    <span class="relative inline-flex shrink-0 {{ $dotSize }}">
        @if ($motion === 'ping')
            <span data-slot="status-dot-ping" aria-hidden="true" class="{{ $status['pingBase'] }} {{ $pingColour }}"></span>
        @endif
        <span data-slot="status-dot" aria-hidden="true" class="{{ $status['dotBase'] }} {{ $dotSize }} {{ $dotColour }} {{ $motion === 'pulse' ? $status['pulseDot'] : '' }}"></span>
    </span>

    @if ($label !== null)
        <span data-slot="status-label" class="{{ $appearance === 'pill' ? 'leading-none' : $status['labelBase'].' '.$sizeStyles['text'] }}">{{ $label }}</span>
    @else
        {{-- No visible label: give screen readers the variant name --}}
        <span class="sr-only">{{ ucfirst($variant) }}</span>
    @endif
</span>

Ownership & lifecycle

Owner, release state, review evidence and adoption for this item.
Owner
Platform UI (@JoshJML)
Current version
1.4.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