brackets/admin-ui
Brackets Admin UI is a Laravel package for building consistent admin panels faster, with reusable Blade components, layouts, navigation, forms, tables, and UI helpers for back-office interfaces.
brackets/admin-ui is the presentation layer of the BRACKETS/Craftable stack: an admin shell (layout, sidebar/menu, assets, breadcrumbs, translations) plus an AdminUI facade you use to register menu entries, custom scripts, styles, and Vue modules. It is not a full admin framework on its own — day to day you pair it with brackets/admin-auth (separate admin guard, admin_users table, login screens) and usually brackets/admin-generator (CRUD scaffolding).
Minimal setup:
composer require brackets/admin-ui # pulls admin-auth in most setups
php artisan vendor:publish --provider="Brackets\AdminUI\AdminUIServiceProvider" # config, assets, views, lang
php artisan migrate # admin_users + activation/password-reset tables
php artisan storage:link
php artisan admin:create-user # or seed an AdminUser row directly
Then log in at /admin (prefix is configurable). If the command name differs in your version, php artisan list | grep -i admin will show what's shipped.
Where to look first, in this order:
vendor/brackets/admin-ui/src/AdminUI.php — the facade. This file is the extension API; read it before anything else.resources/views/layouts/admin.blade.php and partials/sidebar.blade.php — the shell and menu rendering, including which @yield/@section names you can hook into.config/admin-ui.php (after publishing) — route prefix, middleware, and any menu/asset defaults.vendor/brackets/admin-auth/routes/ — confirm the guard name (admin), login route, and middleware group you must reuse.First use case: an internal back office for a small SaaS — one generated CRUD (e.g. Article or Order), a couple of dashboard counters, and a menu entry per domain area. That covers ~90% of real usage.
Register everything from a service provider, not from views. Menu items, scripts, and modules belong in AppServiceProvider::boot() (or a dedicated AdminServiceProvider) so they survive route/view caching and are testable:
use Brackets\AdminUI\Facades\AdminUI;
public function boot(): void
{
AdminUI::addMenuItem(/* label, route/url, icon, ordering */);
AdminUI::registerCustomScript(public_path('js/admin/custom.js'));
AdminUI::registerCustomStyle(public_path('css/admin/custom.css'));
}
Confirm exact signatures against src/AdminUI.php for your installed version — the API has grown over releases and older tutorials show pre-2023 method names.
Custom admin pages = guarded route group + a Blade view extending the admin layout. Reuse the same middleware stack as the package routes so session/guard behaviour matches:
Route::middleware(['web', 'auth:admin'])
->prefix(config('admin-ui.route_prefix', 'admin'))
->group(function () {
Route::get('reports', ReportController::class)->name('admin.reports');
});
@extends('admin-ui::layouts.admin')
@section('content')
{{-- Bootstrap 4 markup; the shell does not ship Tailwind --}}
@endsection
Generate, then own the code. Run admin-generator for each model, then treat the generated controllers, requests, and views as application code — commit them and edit freely. Regenerating over an edited controller is the fastest way to lose work; generate once, then diff if you must re-run.
Brand it at the SCSS layer, not with CSS overrides. Publish assets, change the primary colour variable, recompile, and re-publish (--force). Ad-hoc overrides in a <style> block tend to break on the next package upgrade because class names aren't part of the public API.
Dashboard widgets: the dashboard is just a view. Publish views and replace the dashboard blade with your own partials; register any JS you need through AdminUI::registerCustomScript() rather than editing the layout, so upgrades stay mergeable.
Authorization: the admin guard uses its own user model, so Laravel's default auth middleware and Gate definitions won't apply automatically. Define policies against the admin user model and check permissions (Spatie) inside controllers — don't assume auth()->user() returns the right model inside admin routes.
Linking out: admin lists frequently need a "view on site" action. Keep those URLs in named front-end routes and reference them from the admin controller/views rather than hardcoding paths.
auth:admin. Mixing auth and auth:admin in the same route group produces silent 302 loops back to /admin/login. Also configure a separate password broker if you want admin password resets.composer update, always re-publish assets with --force and clear the view cache. The classic symptom is "my JS changes don't appear" or a blank sidebar because a published view references a removed partial.vendor/) so package upgrades don't silently regress.registerCustomScript/registerCustomStyle point at real public paths. A missing file produces a 404 buried in the admin <head> and a broken page with no server-side error. Assert file existence in your provider during local dev.route:cache. Resolve DB-driven menu data in a view composer or middleware, not in boot().php artisan permission:cache-reset. Bake this into your deploy script.storage:link or a filesystems.disks mismatch, not the package.AdminUI facade registrations, (2) new routes/controllers/views of your own, (3) published config, (4) published views, (5) editing vendor/. Stay at level 1–2 as long as you can; if you need deep layout surgery, fork the package into packages/ with a VCS/path repository instead of patching vendor files.composer.json — releases are infrequent enough that an unpinned minor bump can move you several Laravel major versions of assumptions at once.How can I help you explore Laravel packages today?