Skip to content
Brok UI

Loading…

No results

Record Tabs

Open source

A line tab strip for a record — one tab per subject with a count and an attention marker, deep-linkable through `?tab=`, panels supplied as named slots keyed by tab.

Version
v1.0.1
Stability
stable
License
MIT
Related
Tabs
Record Section
Quick Drawer

Preview

Overview will appear here.

Lines will appear here.

Payments will appear here.

Shipments will appear here.

History will appear here.

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

Installation

terminal
php artisan ui:add admin-record-tabs

Note

This component ships an Alpine behavior module at resources/js/ui/admin-record-tabs.js. Import it once from your bundle so it registers on alpine:init:

resources/js/ui/index.js JS
import './admin-record-tabs.js';

Registry contract

php artisan ui:add admin-record-tabs 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/record-tabs.blade.php
Registry dependencies
tabs badge
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-record-tabs.md
# Brok UI: Record Tabs (`admin-record-tabs`)

A line tab strip for a record — one tab per subject with a count and an attention marker, deep-linkable through `?tab=`, panels supplied as named slots keyed by tab.

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

## Install

```bash
php artisan ui:add admin-record-tabs
```

## Usage

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

## Props

- `tabs` (array, default `[]`) — [['key','label','count' => null,'attention' => false,'disabled' => false]].
- `default` (string|null, default `null`) — Initially active key; defaults to the first.
- `param` (string|false, default `tab`) — Query key for URL sync; `false` turns it off (inside a drawer).
- `label` (string|null, default `null`) — Accessible name of the tab list.

## Use when

- Use to orient users and help them move across pages, sections, or commands.
- A record has several subjects (overview, lines, payments, history) a person opens it for.
- A colleague must be sent straight to one subject by link.

## Avoid when

- Do not hide primary wayfinding in novelty interactions or deep nested structures if straightforward navigation would be clearer.
- Two or three static content panels on a marketing page — use `tabs` directly.
- Navigation between pages — use links.

## Anti-patterns

- Hiding primary wayfinding in novelty interactions

## Rules

- Use the `<brok:admin-record-tabs>` tag (or `<x-ui.admin-record-tabs>`) 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-record-tabs
- Registry JSON (files, props, contract): https://brokui.dev/r/open/admin-record-tabs.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
tabs array [] [['key','label','count' => null,'attention' => false,'disabled' => false]].
default string | null null Initially active key; defaults to the first.
param string | false tab Query key for URL sync; `false` turns it off (inside a drawer).
label string | null null Accessible name of the tab list.

Slots

  • <tab key> — One slot per tab key holding that panel; a placeholder renders for a tab without one.

Data slots

Stable hooks for CSS overrides and browser tests.

record-tabs

Behavior

  • The tab named in the URL wins over `default` on load; selections are written back with replaceState.
  • The attention marker is a character plus a screen-reader label, never colour alone.
  • Installs a JavaScript behavior module when the registry item includes resources/js/ui files.
  • Declares registry capability flags: a11y, interactive, responsive, rtl, darkMode, localized.

Guidance

Navigation and orientation

Orient users and move between destinations.

Use when

  • Use to orient users and help them move across pages, sections, or commands.
  • A record has several subjects (overview, lines, payments, history) a person opens it for.
  • A colleague must be sent straight to one subject by link.

Avoid when

  • Do not hide primary wayfinding in novelty interactions or deep nested structures if straightforward navigation would be clearer.
  • Two or three static content panels on a marketing page — use `tabs` directly.
  • Navigation between pages — use links.

Use instead

  • Visible links and local navigation

Anti-patterns

  • Hiding primary wayfinding in novelty interactions
Anatomy
record-tabs
Theming hooks
record-tabs

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
  • Roving tabindex, arrow keys, Home/End and swipe come from the tabs primitive; counts are text inside the tab name.
  • 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/record-tabs.blade.php Blade
{{--
    Record Tabs — one tab per subject a person opens a record for, each
    carrying the count of what it holds and a marker when that subject needs
    a person.

    The Overview tab comes first: a short sheet answers most visits without
    a second click. The marker is a character, not only a colour, so it
    survives a colour-deficient reader and a monochrome screen, and it is
    named for a screen reader. Tabs are deep-linkable (`?tab=…`) through the
    tabs primitive's `param`, so a colleague can be sent straight to the
    History of a record.

    Panels are named slots keyed by the tab: `<x-slot:overview>`,
    `<x-slot:history>`. A tab without a slot renders a placeholder panel so
    the strip stays honest while a screen is still being built.

    Generalised from the Noord-C admin's `profile/tabs.blade.php` and the
    nineteen per-module tab strips that repeated it.
--}}
@props([
    'tabs' => [],
    'default' => null,
    // Query key the active tab is read from and written to; `false` turns
    // deep-linking off (a tab strip inside a drawer must not touch the URL).
    'param' => 'tab',
    'label' => null,
])

@php
    // Shapes documented in item.json knowledge.props:
    //   tabs: [['key', 'label', 'count' => null, 'attention' => false, 'disabled' => false]]
    $tabs = $tabs !== [] ? $tabs : [
        ['key' => 'overview', 'label' => __('Overview')],
        ['key' => 'lines', 'label' => __('Lines'), 'count' => 4],
        ['key' => 'payments', 'label' => __('Payments'), 'count' => 2, 'attention' => true],
        ['key' => 'shipments', 'label' => __('Shipments'), 'count' => 1],
        ['key' => 'history', 'label' => __('History'), 'count' => 12],
    ];
    $tabs = array_values(array_filter((array) $tabs, 'is_array'));

    $default ??= $tabs[0]['key'] ?? null;
    $label ??= __('Record sections');
@endphp

<x-ui.tabs
    variant="line"
    :default="$default"
    :param="$param ?: null"
    data-surface="admin"
    {{ $attributes->merge(['class' => 'min-w-0 gap-6']) }}
>
    <div data-slot="record-tabs" class="min-w-0 overflow-x-auto">
        <x-ui.tabs.list :aria-label="$label" class="w-full min-w-max">
            @foreach ($tabs as $tab)
                <x-ui.tabs.trigger :value="$tab['key']" :disabled="$tab['disabled'] ?? false" :data-attention="($tab['attention'] ?? false) ? 'true' : null">
                    <span>{{ $tab['label'] ?? $tab['key'] }}</span>

                    @if (($tab['count'] ?? null) !== null)
                        <x-ui.badge variant="soft-neutral" size="sm" class="tabular-nums">{{ $tab['count'] }}</x-ui.badge>
                    @endif

                    @if ($tab['attention'] ?? false)
                        <span class="font-bold text-destructive-text" aria-hidden="true">!</span>
                        <span class="sr-only">{{ __('needs attention') }}</span>
                    @endif
                </x-ui.tabs.trigger>
            @endforeach
        </x-ui.tabs.list>
    </div>

    @foreach ($tabs as $tab)
        @php
            $key = $tab['key'];
            // A named slot arrives as a variable of the same name; only a real
            // slot counts, never a prop or a loop variable that happens to share
            // the key.
            $panel = isset($$key) && $$key instanceof \Illuminate\View\ComponentSlot ? $$key : null;
        @endphp
        <x-ui.tabs.content :value="$key" data-record-tab="{{ $key }}">
            @if ($panel !== null)
                {{ $panel }}
            @else
                <p class="text-sm text-muted-foreground">
                    {{ __(':label will appear here.', ['label' => $tab['label'] ?? $key]) }}
                </p>
            @endif
        </x-ui.tabs.content>
    @endforeach
</x-ui.tabs>

Ownership & lifecycle

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