Skip to content
Brok UI

Loading…

No results

Page State

Open source

Full-page loading, empty, error, and ready state contracts.

Preview

resources/views/blocks/page-state-application.blade.php Blade
@props([
    'state' => 'empty',
    'title' => null,
    'description' => null,
    'actionHref' => null,
    'actionLabel' => 'Create item',
    'retryHref' => null,
    'retryLabel' => 'Try again',
    'supportReference' => null,
])

@php
    $state = in_array($state, ['loading', 'empty', 'error', 'ready'], true) ? $state : 'empty';
    $title ??= match ($state) {
        'loading' => 'Loading page',
        'error' => 'We could not load this page',
        'ready' => 'Page content',
        default => 'No items yet',
    };
    $description ??= match ($state) {
        'loading' => 'The latest data is loading.',
        'error' => 'Try the request again. Contact support if the problem continues.',
        'ready' => 'The requested content is ready.',
        default => 'Create the first item to start this workflow.',
    };
@endphp

<section
    data-slot="page-state"
    data-state="{{ $state }}"
    data-surface="admin"
    data-visual-contracts="VC-009"
    @if ($state === 'loading') aria-busy="true" @endif
    {{ $attributes->merge(['class' => 'grid min-h-[28rem] place-items-center bg-background p-4 text-foreground sm:p-8']) }}
>
    <div class="w-full max-w-3xl">
        <x-ui.card class="overflow-hidden">
        @if ($state === 'loading')
            <div role="status" class="space-y-6 p-6 sm:p-8">
                <span class="sr-only">{{ __($description) }}</span>
                <div class="space-y-4">
                    <x-ui.skeleton class="h-8 w-2/5" />
                    <x-ui.skeleton class="h-4 w-4/5" />
                </div>
                <div class="grid gap-4 sm:grid-cols-2">
                    <x-ui.skeleton shape="rounded" class="h-28" />
                    <x-ui.skeleton shape="rounded" class="h-28" />
                    <x-ui.skeleton shape="rounded" class="h-28" />
                    <x-ui.skeleton shape="rounded" class="h-28" />
                </div>
            </div>
        @elseif ($state === 'error')
            <x-ui.alert variant="destructive" class="p-6 sm:p-8">
                <h2 class="text-lg font-semibold">{{ __($title) }}</h2>
                <p class="mt-2 text-sm">{{ __($description) }}</p>
                @if ($supportReference)
                    <p class="mt-4 font-mono text-xs">{{ __('Reference: :reference', ['reference' => $supportReference]) }}</p>
                @endif
                @if ($retryHref)
                    <div class="mt-6">
                        <x-ui.button :href="$retryHref" variant="outline">{{ __($retryLabel) }}</x-ui.button>
                    </div>
                @endif
            </x-ui.alert>
        @elseif ($state === 'ready')
            <div aria-live="polite">
                @if ($slot->isEmpty())
                    <x-ui.card.header>
                        <x-ui.card.title>{{ __($title) }}</x-ui.card.title>
                        <x-ui.card.description>{{ __($description) }}</x-ui.card.description>
                    </x-ui.card.header>
                @else
                    {{ $slot }}
                @endif
            </div>
        @else
            <x-ui.empty>
                <div class="grid size-12 place-items-center rounded-full bg-muted text-muted-foreground" aria-hidden="true">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" class="size-6"><path d="M4 7.5h16v11H4zM8 7.5V5.8A1.8 1.8 0 0 1 9.8 4h4.4A1.8 1.8 0 0 1 16 5.8v1.7" /></svg>
                </div>
                <div>
                    <h2 class="text-lg font-semibold">{{ __($title) }}</h2>
                    <p class="mt-2 text-sm text-muted-foreground">{{ __($description) }}</p>
                </div>
                @if ($actionHref)
                    <x-ui.button :href="$actionHref">{{ __($actionLabel) }}</x-ui.button>
                @endif
            </x-ui.empty>
        @endif
        </x-ui.card>
    </div>
</section>

Installation

terminal
php artisan ui:add blocks/page-state-application

Installs these dependencies automatically:

Registry contract

Install confidence

php artisan ui:add blocks/page-state-application writes only the generated targets below. The CLI validates each file hash before writing and prompts before replacing local changes unless --force is used.

Version
1.1.3
License
open
Stability
stable
Contract
v2
Foundation
≥ 1.0.0
Type Generated target
blade resources/views/blocks/page-state-application.blade.php

Registry dependencies

skeleton empty alert button card

Package dependencies

composer: jml/brok:^0.2

Use with AI

A brief for your coding agent: what the block is, the install command, how to render it, its props and the rules. Copy it, or open a prompt about this block in an assistant.

page-state-application.md
# Brok UI block: Page State (`page-state-application`)

A full-page state contract for stable loading skeletons, actionable empty states, recoverable errors, and ready content.

Brok UI is a Laravel Blade registry. `ui:add` copies this block into the app as plain Blade the app owns; it composes installed `<brok:*>` primitives and semantic design tokens.

## Install

```bash
php artisan ui:add blocks/page-state-application
```

## Render it

```blade
<x-blocks.page-state-application />
```

## Props

- `state` (loading|empty|error|ready, default `empty`) — Selects the state contract.
- `title` (string|null, default `null`) — State heading.
- `description` (string|null, default `null`) — State explanation.
- `action-href` (string|null, default `null`) — Empty-state primary destination.
- `action-label` (string, default `Create item`) — Empty-state primary action label.
- `retry-href` (string|null, default `null`) — Error retry destination.
- `retry-label` (string, default `Try again`) — Error retry action label.
- `support-reference` (string|null, default `null`) — Safe support correlation reference.

## Use when

- Use when one page region switches between loading, empty, failed, and ready states.

## Avoid when

- Use local skeleton, empty, or alert primitives when only one small widget changes state.

## Rules

- Render the installed block with `<x-blocks.page-state-application />` and pass data through its props; edit the copied file only for structural changes.
- Keep the semantic design tokens (`bg-background`, `text-muted-foreground`); never swap in raw colour utilities.
- Keep the `data-slot` attributes and the logical (start/end) spacing so the markup still mirrors under `dir="rtl"`.

## Links

- Docs: https://brokui.dev/blocks/page-state-application
- Registry JSON (files, props, contract): https://brokui.dev/r/open/blocks/page-state-application.json

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

Guidance

Use when

  • Use when one page region switches between loading, empty, failed, and ready states.

Avoid when

  • Use local skeleton, empty, or alert primitives when only one small widget changes state.

Anti-patterns

  • Do not replace semantic props with conflicting utility classes.
  • Do not remove labels, focus styles, or state attributes.
Anatomy
stable page frame state message loading shape primary next action retry and support reference ready content
Theming hooks
Uses the admin surface and semantic design tokens.

Usage

Render the block as a component, passing data where useful:

resources/views/welcome.blade.php Blade
<x-blocks.page-state-application />

Built from primitives

Composes <brok:*> Semantic tokens Re-themeable RTL-ready

This block composes installed <brok:*> primitives and semantic design tokens only — it does not reimplement any primitive. Re-theme it (light, dark, admin, customer) by editing CSS variables; flip the preview to RTL to confirm it mirrors.

Source

The exact, editable file ui:add writes into your app. The preview above renders this same source — there are no preview-only blocks.

resources/views/blocks/page-state-application.blade.php Blade
@props([
    'state' => 'empty',
    'title' => null,
    'description' => null,
    'actionHref' => null,
    'actionLabel' => 'Create item',
    'retryHref' => null,
    'retryLabel' => 'Try again',
    'supportReference' => null,
])

@php
    $state = in_array($state, ['loading', 'empty', 'error', 'ready'], true) ? $state : 'empty';
    $title ??= match ($state) {
        'loading' => 'Loading page',
        'error' => 'We could not load this page',
        'ready' => 'Page content',
        default => 'No items yet',
    };
    $description ??= match ($state) {
        'loading' => 'The latest data is loading.',
        'error' => 'Try the request again. Contact support if the problem continues.',
        'ready' => 'The requested content is ready.',
        default => 'Create the first item to start this workflow.',
    };
@endphp

<section
    data-slot="page-state"
    data-state="{{ $state }}"
    data-surface="admin"
    data-visual-contracts="VC-009"
    @if ($state === 'loading') aria-busy="true" @endif
    {{ $attributes->merge(['class' => 'grid min-h-[28rem] place-items-center bg-background p-4 text-foreground sm:p-8']) }}
>
    <div class="w-full max-w-3xl">
        <x-ui.card class="overflow-hidden">
        @if ($state === 'loading')
            <div role="status" class="space-y-6 p-6 sm:p-8">
                <span class="sr-only">{{ __($description) }}</span>
                <div class="space-y-4">
                    <x-ui.skeleton class="h-8 w-2/5" />
                    <x-ui.skeleton class="h-4 w-4/5" />
                </div>
                <div class="grid gap-4 sm:grid-cols-2">
                    <x-ui.skeleton shape="rounded" class="h-28" />
                    <x-ui.skeleton shape="rounded" class="h-28" />
                    <x-ui.skeleton shape="rounded" class="h-28" />
                    <x-ui.skeleton shape="rounded" class="h-28" />
                </div>
            </div>
        @elseif ($state === 'error')
            <x-ui.alert variant="destructive" class="p-6 sm:p-8">
                <h2 class="text-lg font-semibold">{{ __($title) }}</h2>
                <p class="mt-2 text-sm">{{ __($description) }}</p>
                @if ($supportReference)
                    <p class="mt-4 font-mono text-xs">{{ __('Reference: :reference', ['reference' => $supportReference]) }}</p>
                @endif
                @if ($retryHref)
                    <div class="mt-6">
                        <x-ui.button :href="$retryHref" variant="outline">{{ __($retryLabel) }}</x-ui.button>
                    </div>
                @endif
            </x-ui.alert>
        @elseif ($state === 'ready')
            <div aria-live="polite">
                @if ($slot->isEmpty())
                    <x-ui.card.header>
                        <x-ui.card.title>{{ __($title) }}</x-ui.card.title>
                        <x-ui.card.description>{{ __($description) }}</x-ui.card.description>
                    </x-ui.card.header>
                @else
                    {{ $slot }}
                @endif
            </div>
        @else
            <x-ui.empty>
                <div class="grid size-12 place-items-center rounded-full bg-muted text-muted-foreground" aria-hidden="true">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" class="size-6"><path d="M4 7.5h16v11H4zM8 7.5V5.8A1.8 1.8 0 0 1 9.8 4h4.4A1.8 1.8 0 0 1 16 5.8v1.7" /></svg>
                </div>
                <div>
                    <h2 class="text-lg font-semibold">{{ __($title) }}</h2>
                    <p class="mt-2 text-sm text-muted-foreground">{{ __($description) }}</p>
                </div>
                @if ($actionHref)
                    <x-ui.button :href="$actionHref">{{ __($actionLabel) }}</x-ui.button>
                @endif
            </x-ui.empty>
        @endif
        </x-ui.card>
    </div>
</section>

Ownership & lifecycle

Owner, release state, review evidence and adoption for this item.
Owner
Platform UI (@JoshJML)
Current version
1.1.3
Status
Stable
License
open
Deprecation
Not deprecated
Contract
v2
Foundation
≥ 1.0.0