nasirkhan / laravel-admin
Tailwind/Flowbite backend shell for Laravel — sidebar, header, breadcrumb layout
Requires
- php: ^8.2
- illuminate/notifications: ^11|^12|^13
- illuminate/routing: ^11|^12|^13
- illuminate/support: ^11|^12|^13
Requires (Dev)
None
Suggests
- livewire/livewire: Required for Livewire-powered index tables (UsersIndex, RolesIndex).
- spatie/laravel-permission: Required for role and permission management.
Provides
None
Conflicts
None
Replaces
None
README
A Tailwind CSS / Flowbite backend shell for Laravel — sidebar, header, breadcrumb layout.
This package provides the structural layout (sidebar, top navigation, main content wrapper) for a Laravel admin panel. It is designed to work alongside laravel-cube for UI components, but the core layout works independently.
Requirements
- PHP ^8.2
- Laravel 11 / 12 / 13
- Tailwind CSS v4 + Flowbite (compiled via Vite in the host application)
Installation
composer require nasirkhan/laravel-admin
The service provider is auto-discovered.
Publish assets
Publish the config file:
php artisan vendor:publish --tag=admin-config
Publish the views (only if you need to customise them):
php artisan vendor:publish --tag=admin-views
Configuration
After publishing, edit config/admin.php:
return [ // Brand name shown in the sidebar and browser tab 'name' => env('APP_NAME', 'Admin'), // Optional logo path relative to public/ (null = text brand) 'logo' => null, // Default theme: 'system' | 'light' | 'dark' 'theme' => 'system', // Fallback navigation when no dynamic menu (module-manager) is available 'nav' => [ [ 'label' => 'Dashboard', 'route' => 'backend.dashboard', 'icon' => 'home', 'children' => [], ], [ 'label' => 'Users', 'route' => 'backend.users.index', 'icon' => 'users', 'children' => [], ], [ 'label' => 'Roles', 'route' => 'backend.roles.index', 'icon' => 'shield', 'children' => [], ], [ 'label' => 'Notifications', 'route' => 'backend.notifications.index', 'icon' => 'bell', 'children' => [], ], ], ];
Supported icon values: home, users, shield, bell, cog.
What's included
Beyond the layout shell, the package ships a complete backend for the three core resources:
| Resource | Routes (prefix admin/) |
Controller |
|---|---|---|
| Dashboard | GET /, GET /dashboard |
BackendController |
| Users | CRUD + block/unblock/trash/restore/change-password | UserController |
| Roles | CRUD + permission sync | RolesController |
| Notifications | index / show / mark-all-read / delete-all | NotificationsController |
All routes are named under the backend. prefix (e.g. backend.users.index) and protected by the auth and can:view_backend middleware.
Four Livewire components are registered by the package:
| Alias | Class |
|---|---|
admin.dashboard |
Nasirkhan\Admin\Livewire\AdminDashboard |
admin.notifications |
Nasirkhan\Admin\Livewire\Notifications |
backend.users-index |
Nasirkhan\Admin\Livewire\UsersIndex |
backend.roles-index |
Nasirkhan\Admin\Livewire\RolesIndex |
Controllers intentionally keep use App\Models\User and use App\Models\Role — models stay in the host application.
Customising views
Published views in the host application always take precedence over the package defaults. You can override any view without touching the package.
Publish all views at once
php artisan vendor:publish --tag=admin-views
Files land in resources/views/vendor/admin/ with the same structure as the package:
resources/views/vendor/admin/
├── users/
│ ├── index.blade.php
│ ├── create.blade.php
│ ├── edit.blade.php
│ ├── show.blade.php
│ ├── changePassword.blade.php
│ └── trash.blade.php
├── roles/
│ ├── index.blade.php
│ ├── create.blade.php
│ ├── edit.blade.php
│ └── show.blade.php
├── notifications/
│ ├── index.blade.php
│ └── show.blade.php
├── includes/
│ ├── action_column.blade.php
│ ├── errors.blade.php
│ ├── show.blade.php
│ ├── user_actions.blade.php
│ └── user_roles.blade.php
└── livewire/
├── dashboard.blade.php
├── notifications.blade.php
├── users-index.blade.php
└── roles-index.blade.php
Publish selectively
Copy only the files you need to override. For example, to override just the user edit form:
mkdir -p resources/views/vendor/admin/users cp vendor/nasirkhan/laravel-admin/resources/views/users/edit.blade.php \ resources/views/vendor/admin/users/edit.blade.php
Laravel resolves admin::users.edit by looking in resources/views/vendor/admin/ first, then falling back to the package.
Publish everything (views + config + routes)
php artisan vendor:publish --provider="Nasirkhan\Admin\AdminServiceProvider"
Adding columns to the users table
To add a new field (e.g. phone) to user management:
1. Create and run a migration
php artisan make:migration add_phone_to_users_table --table=users php artisan migrate
2. Add the column to $fillable in App\Models\User
protected $fillable = ['name', 'email', 'phone', ...];
3. Publish the views you need to change (if not already published)
php artisan vendor:publish --tag=admin-views
4. Edit the published views
resources/views/vendor/admin/users/create.blade.php— add the form fieldresources/views/vendor/admin/users/edit.blade.php— add the field with its old/current valueresources/views/vendor/admin/users/show.blade.php— add a display row
5. Optional — make the column visible in the listing
Publish and edit resources/views/vendor/admin/livewire/users-index.blade.php to add a column to the table. If the column also needs to be searchable or sortable, publish the Livewire component class by copying it into your app and re-registering it in a service provider:
// In your AppServiceProvider::boot() \Livewire\Livewire::component('backend.users-index', \App\Livewire\Admin\UsersIndex::class);
Customising the Dashboard
The dashboard is powered by the admin.dashboard Livewire component (AdminDashboard class) and its view admin::livewire.dashboard. Both are designed to be overridden without touching the package.
Remove the demo data
The default dashboard includes a demo data include. To remove it, publish the main dashboard view and delete the include line:
php artisan vendor:publish --tag=admin-views
Then open resources/views/vendor/admin/index.blade.php and remove:
@include("admin::includes.dashboard_demo_data")
Add or change stat cards (view only)
If you only need to change the layout or copy of the cards — no new database queries — override just the Livewire view:
mkdir -p resources/views/vendor/admin/livewire cp vendor/nasirkhan/laravel-admin/resources/views/livewire/dashboard.blade.php \ resources/views/vendor/admin/livewire/dashboard.blade.php
Edit the published file. Each card follows this structure:
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-100 dark:border-gray-700 overflow-hidden"> <div class="flex items-center gap-4 p-5"> <div class="flex-shrink-0 flex items-center justify-center w-12 h-12 rounded-xl bg-blue-600 text-white shadow-sm"> <i class="fa-solid fa-newspaper text-lg"></i> </div> <div> <div class="text-3xl font-bold text-gray-900 dark:text-white leading-none">{{ $postsCount }}</div> <div class="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mt-1">@lang('Posts')</div> </div> </div> <div class="border-t border-gray-100 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/50 px-5 py-2.5"> <a href="{{ route('backend.posts.index') }}" class="flex items-center justify-between text-blue-600 hover:text-blue-700 dark:text-blue-400 transition-colors group"> <span class="text-xs font-semibold">@lang('View all posts')</span> <i class="fa-solid fa-arrow-right text-xs group-hover:translate-x-0.5 transition-transform"></i> </a> </div> </div>
The grid wrapping the cards uses grid-cols-1 sm:grid-cols-2 lg:grid-cols-5. Adjust the last class to match the number of cards you have (e.g. lg:grid-cols-3 for three cards).
Add a card that needs new data (class + view)
When a new card needs a count or query that the base component does not expose, extend AdminDashboard and re-register the alias.
1. Create the extended component
// app/Livewire/Admin/AdminDashboard.php namespace App\Livewire\Admin; use Nasirkhan\Admin\Livewire\AdminDashboard as BaseAdminDashboard; class AdminDashboard extends BaseAdminDashboard { public int $commentsCount; public function mount(): void { parent::mount(); // keeps the existing counts $this->commentsCount = \App\Models\Comment::count(); } }
2. Re-register the Livewire alias
Because AppServiceProvider boots after AdminServiceProvider, registering the alias again replaces the package's class:
// app/Providers/AppServiceProvider.php use Livewire\Livewire; public function boot(): void { Livewire::component('admin.dashboard', \App\Livewire\Admin\AdminDashboard::class); }
3. Override the view and add the card
Publish the Livewire view (if you haven't already) and add a new card block that references $commentsCount:
mkdir -p resources/views/vendor/admin/livewire cp vendor/nasirkhan/laravel-admin/resources/views/livewire/dashboard.blade.php \ resources/views/vendor/admin/livewire/dashboard.blade.php
Then add a card for {{ $commentsCount }} inside the grid in the published file.
Overriding the Notifications component
The same pattern applies to the Notifications component:
| What to override | Path |
|---|---|
| View only | resources/views/vendor/admin/livewire/notifications.blade.php |
| Class | Extend Nasirkhan\Admin\Livewire\Notifications, re-register admin.notifications |
Usage
Extend the admin layout in your backend Blade views:
@extends('admin::layouts.admin') @section('title', 'Dashboard') @section('breadcrumbs') {{-- optional breadcrumb markup --}} @endsection @section('content') <p>Your page content goes here.</p> @endsection
Layout slots
| Section / Stack | Purpose |
|---|---|
title |
Browser tab / page title |
breadcrumbs |
Rendered inside the top navbar |
content |
Main page body |
@stack('styles') |
Extra <style> or <link> tags in <head> |
@stack('scripts') |
Extra <script> tags before </body> |
Vite setup
The layout expects two Vite entry points compiled in the host application:
// vite.config.js export default defineConfig({ plugins: [ laravel({ input: [ 'resources/css/app-backend.css', 'resources/js/app-backend.js', ], }), ], });
app-backend.css should import Tailwind CSS v4 and Flowbite:
@import 'tailwindcss'; @import 'flowbite/src/flowbite.css'; @source '../views/backend/**/*.blade.php'; @source '../../vendor/nasirkhan/laravel-admin/resources/views/**/*.blade.php';
Optional integrations
| Package | Effect |
|---|---|
nasirkhan/laravel-cube |
Enables language switcher, Google Analytics, and dynamic menu components |
nasirkhan/module-manager |
Enables database-driven dynamic sidebar navigation |
These integrations are detected at runtime — the layout degrades gracefully without them.
Dark mode
Dark mode is toggled via a button in the top navbar and persisted in localStorage under the key color-theme. The <html> tag receives the dark class (Tailwind class-based dark mode).
License
GPL-3.0-or-later — see LICENSE.