⌘K

Admin

The Layout

The Blade component your layout names, the slots it exposes, the auth frame beside it, and where the signed-in user goes.

On this page

The shell is a Blade component, not a configuration object. Your layout view names it and fills its slots — which is why brand, auth and chrome are markup you write rather than a class you configure.

Slots

Slot Where it lands Typical content
head in <head>, before Livewire's own tags @vite(...), meta tags, a font
brand left of the top bar an application name, a logo
topbar the top bar, after the palette trigger a tenant switcher, breadcrumbs
user the end of the top bar an account menu, a sign-out form
(default) the <main> element the page

Slots rather than configuration is deliberate: a class holding brand, colours and auth is what pulls a panel builder into being, and everything one would carry is markup you can already write.

The Menu As A Bar

From lg up the menu is a column beside the page by default. It can be a bar under the header instead — for an application with few top-level sections and wide tables that want the width:

// config/wire-admin.php
'layout' => [
'navigation' => 'top', // 'sidebar' (default) | 'top'
],

or for one layout only, <x-wire-admin::layout navigation="top">. A value that names neither is refused with a NavigationShapeException, rather than quietly drawing the column.

The bar draws the same menu the column draws — the same Workspace, the same active entry — in its own shape:

In the column In the bar
a group is a heading over its rows a group is a button opening a panel of its rows
an entry without a group is a row it is a link in the bar
a group of one entry is a heading and a row it is a link — a panel of one row is a click for nothing
children are a list under their parent they are indented under it inside the same panel
what does not fit scrolls what does not fit goes under More at the end of the bar

Below lg it is the drawer, whatever the shape. A bar is a shape for a wide screen; on a phone the column is still the menu, opened from the header. So the document carries both, and the bar's rows are named apart (admin-topnav-*) from the drawer's (admin-nav-*) — shared names would have every test counting each row twice.

The bar never wraps. It is clipped from the first paint, and once the browser has measured it, the entries that do not fit — the first one that does not, and every one after it, so the order holds — are shown under More instead. There is nothing to collapse in a bar, so the rail toggle and its shortcut are not drawn.

From the keyboard, ← and → move along the bar, ↓ on a group opens its panel with focus on the first link, ↑ and ↓ move inside it, and Escape or Tab closes it — Escape handing focus back to the button.

Signing In

The shell has an auth frame and no authentication: <x-wire-admin::auth-layout> is a centered card with the same head — the theme decision, the assets, the interaction layer — and no menu, no palette and no bell, because none of them mean anything before a user exists.

{{-- resources/views/auth/login.blade.php, rendered by Fortify or Breeze --}}
<x-wire-admin::auth-layout :title="__('Sign in')">
<x-slot:brand>{{ config('app.name') }}</x-slot:brand>
<x-slot:footer><a href="{{ route('password.request') }}">{{ __('Forgot your password?') }}</a></x-slot:footer>
 
<form method="POST" action="{{ route('login') }}">@csrf
{{-- your fields --}}
</form>
</x-wire-admin::auth-layout>

Laravel owns the rest, and deliberately: Fortify (headless) or Breeze (scaffolding) already carry login throttling, password-reset tokens and their expiry, email verification, two-factor and session fixation. A panel that reimplements those owns a security surface without gaining a feature, so this package ships the card and not one credential. Where you do want the two-factor setup screen inside the panel, the users module supplies the card and drives Fortify's own actions — a screen over the owner, not a second owner.

What connects the two is middleware you already write:

Route::middleware(['web', 'auth'])->prefix('admin')->group(fn () => Route::wireResources());

Per zone if an application has several — can:admin on one group, can:business on another — and per page through RoutePage::make($page)->permission('users.manage'), which becomes Laravel's own can: middleware. Gate answers all of it, so Spatie's roles and nyoncode/laravel-permission-extended's wildcards work without this package knowing they exist.

Who Is Signed In

The shell shows the signed-in user in the corner, with a menu. It ships no profile page and no sign-out route, because it owns no auth — those arrive in the user-menu slot, and <x-wire-admin::menu-item> is there so what you put in it looks like the menu it sits in:

<x-slot:user-menu>
<x-wire-admin::menu-item :href="route('profile')" icon="outline:user-circle">
Profile
</x-wire-admin::menu-item>
 
<form method="POST" action="{{ route('logout') }}">
@csrf
<x-wire-admin::menu-item type="submit" icon="outline:arrow-right-start-on-rectangle">
Sign out
</x-wire-admin::menu-item>
</form>
</x-slot:user-menu>

The users module ships a profile page for the signed-in user, if you want one rather than writing it.