shopper/sidebar
Headless Laravel sidebar builder with configurable groups, items, icons, weights, nesting, and responsive collapse support. Includes middleware-based sidebar resolution, optional view publishing for customization, and configurable caching (static/user-based) plus width and breakpoint options.
Installation
Run composer require shopper/sidebar and publish the config with:
php artisan vendor:publish --provider="Shopper\Sidebar\SidebarServiceProvider" --tag="sidebar-config"
Middleware Setup
Add the middleware to your web group in bootstrap/app.php (Laravel 11+):
->withMiddleware(function (Middleware $middleware) {
$middleware->appendToGroup('web', \Shopper\Sidebar\Middleware\ResolveSidebars::class);
});
Or wrap routes in a group:
Route::middleware(['web', \Shopper\Sidebar\Middleware\ResolveSidebars::class])->group(...);
First Use Case Define a sidebar in a controller or service:
use Shopper\Sidebar\Facades\Sidebar;
public function showDashboard() {
Sidebar::set('dashboard', [
['type' => 'link', 'url' => '/dashboard', 'label' => 'Dashboard'],
['type' => 'divider'],
['type' => 'link', 'url' => '/settings', 'label' => 'Settings'],
]);
return view('dashboard');
}
Render it in a Blade view:
@include('sidebar::sidebar')
Dynamic Sidebar Management
Use the Sidebar facade to conditionally build sidebars:
if (auth()->user()->isAdmin()) {
Sidebar::set('admin', [
['type' => 'link', 'url' => '/admin/users', 'label' => 'Users'],
]);
}
Reusable Sidebar Components Create a service class to encapsulate sidebar logic:
class SidebarBuilder {
public function buildAdminSidebar() {
return [
['type' => 'header', 'label' => 'Admin Panel'],
['type' => 'link', 'url' => '/admin', 'label' => 'Home'],
];
}
}
Call it in a controller:
Sidebar::set('admin', (new SidebarBuilder())->buildAdminSidebar());
View Integration Extend the default sidebar view by publishing and customizing:
php artisan vendor:publish --tag="sidebar-views"
Override resources/views/vendor/sidebar/sidebar.blade.php to add custom classes or logic.
API-Driven Sidebars Fetch sidebar items from an API or database:
$sidebarItems = SidebarItem::where('user_id', auth()->id())->get();
Sidebar::set('user', $sidebarItems->map(fn ($item) => [
'type' => 'link',
'url' => $item->url,
'label' => $item->label,
]));
width and breakpoint config values in your CSS/JS for responsive design.Route::middleware(['auth', \Shopper\Sidebar\Middleware\ResolveSidebars::class])->group(...);
user-based caching for personalized sidebars:
'cache' => [
'method' => 'user-based',
'duration' => 3600, // 1 hour
],
Middleware Order Matters
Place ResolveSidebars after web middleware to ensure the request is fully processed (e.g., auth checks) before resolving sidebars.
❌ Wrong:
->middleware([\Shopper\Sidebar\Middleware\ResolveSidebars::class, 'auth'])
✅ Correct:
->middleware(['web', 'auth', \Shopper\Sidebar\Middleware\ResolveSidebars::class])
Caching Conflicts
If using user-based caching, ensure auth()->user() is available when the sidebar is resolved. Test with:
php artisan sidebar:clear-cache
View Override Pitfalls Forgetting to clear cached views after publishing custom views may result in stale output. Run:
php artisan view:clear
Type Validation
The package expects strict item types (e.g., 'type' => 'link'). Invalid types may silently fail. Validate with:
$validTypes = ['link', 'header', 'divider', 'dropdown'];
if (!in_array($item['type'], $validTypes)) {
throw new \InvalidArgumentException("Invalid sidebar type: {$item['type']}");
}
dd(\Shopper\Sidebar\Facades\Sidebar::getAll());
public function handle($request, Closure $next) {
try {
return $next($request);
} catch (\Shopper\Sidebar\Exceptions\SidebarException $e) {
\Log::error('Sidebar error: ' . $e->getMessage());
throw $e;
}
}
Custom Sidebar Items
Extend the package by creating a custom item type. Override the SidebarServiceProvider:
public function register() {
$this->app->extend('sidebar', function ($sidebar) {
$sidebar->addType('custom', function ($item) {
return view('sidebar.custom', ['item' => $item]);
});
return $sidebar;
});
}
Database Backend
Replace the default storage with a database-backed solution by binding a custom SidebarRepository:
$this->app->bind(\Shopper\Sidebar\Contracts\SidebarRepository::class, function () {
return new DatabaseSidebarRepository();
});
Event-Based Sidebars Trigger sidebar updates via events (e.g., after user login):
event(new \App\Events\UserLoggedIn(auth()->user()));
Listen for the event and update sidebars:
\App\Events\UserLoggedIn::class => function () {
Sidebar::set('user', [...]);
}
Localization Support Add localized labels to sidebar items dynamically:
Sidebar::set('dashboard', [
['type' => 'link', 'url' => '/dashboard', 'label' => __('sidebar.dashboard')],
]);
How can I help you explore Laravel packages today?