Your first page
This page shows how to add a new admin page to the theme: a view, a route and a menu entry.
Quick example
{{-- resources/views/admin/customers/index.blade.php --}}
@extends('layouts.admin.vertical')
@section('title', __('Customers'))
@section('content')
<acun:page-header :title="__('Customers')" />
@endsection
// routes/web.php
Route::view('/customers', 'admin.customers.index')->name('customers.index');
Open the URL: the page appears inside the panel with its menu, and the tab title is "Customers". In the theme, the panel routes are in a Route::prefix('admin') group. If you put the route inside that group, the URL is /admin/customers.
Step by step
The example adds a "Customers" page to the panel. The same steps apply to every new page.
-
Create the view. Panel pages live under
resources/views/admin/:{{-- resources/views/admin/customers/index.blade.php --}} @extends('layouts.admin.vertical') @section('title', __('Customers')) @section('content') <section class="mx-auto w-full max-w-7xl space-y-6"> <acun:page-header :title="__('Customers')" :breadcrumbs="[['label' => __('Records')], ['label' => __('Customers')]]" /> <acun:card> <acun:empty-state :title="__('No customers yet')" :description="__('Get started by adding your first customer.')"> <acun:slot:action><acun:button>{{ __('New customer') }}</acun:button></acun:slot:action> </acun:empty-state> </acun:card> </section> @endsection@section('title')sets the tab title.@section('content')goes into the content area in the middle of the layout. -
Add the route. If the page shows no data,
Route::viewis enough:// routes/web.php, inside the Route::prefix('admin') group Route::view('/customers', 'admin.customers.index')->name('customers.index');If you need data from the database, write a controller. The controller returns the view with
view('admin.customers.index', [...]), and the route becomesRoute::get('/customers', CustomerController::class). -
Add a line to the menu:
{ "title": "Customers", "icon": "users", "route": "customers.index", "active": "customers.*" }Put the line in the
menuarray of theresources/menu/main.jsonfile. The page appears both in the menu and in the ⌘K search. Thanks toactive, the item also stays selected on subpages such ascustomers.create.
Changing the layout
Change the layout name in the @extends line:
| Layout | When |
|---|---|
layouts.admin.vertical |
Vertical menu on the left; for most pages. |
layouts.admin.horizontal |
Menu in the top bar. |
layouts.admin.blank |
No menu: sign-in, registration and error screens. |
The Layouts page describes what each layout contains and its options.
Livewire page
If the page is interactive (a form, live search), write it as a Livewire component:
// app/Livewire/Customers/Index.php
namespace App\Livewire\Customers;
use Illuminate\Contracts\View\View;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;
#[Layout('layouts.admin.vertical')]
#[Title('Customers')]
final class Index extends Component
{
public function render(): View
{
return view('admin.customers.index');
}
}
{{-- resources/views/admin/customers/index.blade.php --}}
<section class="mx-auto w-full max-w-7xl space-y-6">
<acun:page-header :title="__('Customers')" />
…
</section>
// routes/web.php
use App\Livewire\Customers\Index as CustomersIndex;
Route::livewire('/customers', CustomersIndex::class)->name('customers.index');
#[Layout] places the page inside the layout. #[Title] is the translation key of the tab title; a PHP attribute can't call __(), so the layout translates it. Don't write @extends or @section in a Livewire view. The view starts with a single root element, <section> in the example.
Page-specific script
Push a JavaScript file that should run only on this page to the page-scripts stack:
@push('page-scripts')
@vite('resources/js/pages/customers.js')
@endpush
The layouts print this stack at the end of the page. The CSS, JavaScript and build page explains how to add the file to the Vite inputs.
Authorization
The menu doesn't check permissions. Protect pages that require authorization with your own middleware or policy on the route. To hide the item from the menu, see the Menu page.
Learn more
- List pages: turn the page into a list with search, filters and bulk actions.
- Form modal: a modal for adding and editing records.
- Menu: every field of the menu file.
- Layouts: layout files, slots and props.