juy/active-menu
Laravel helper to add an “active” CSS class based on the current route name. Supports exact, wildcard, and multiple route patterns via facade, container, or helper, plus a Blade directive. Configurable active class value.
Installation:
composer require juy/active-menu
Register Service Provider:
Add Juy\ActiveMenu\ServiceProvider::class to config/app.php under providers.
Publish Config (optional):
php artisan vendor:publish --provider="Juy\ActiveMenu\ServiceProvider" --tag="config"
(Default config is fine unless you need to customize the active class.)
First Use Case:
In a Blade template, check if the current route matches a name (e.g., dashboard) and apply the active class:
<li class="{{ Active::route('dashboard') ? 'active' : '' }}">
<a href="{{ route('dashboard') }}">Dashboard</a>
</li>
Route-Based Active State:
Use Active::route('route.name') to conditionally apply classes to navigation items:
<li class="{{ Active::route(['dashboard', 'settings.index']) ? 'active' : '' }}">
<a href="{{ route('dashboard') }}">Dashboard</a>
</li>
(Supports arrays for multiple route names.)
Dynamic Navigation Menus: Loop through menu items and check each route dynamically:
$menuItems = [
['name' => 'Dashboard', 'route' => 'dashboard'],
['name' => 'Profile', 'route' => 'profile.edit'],
];
@foreach($menuItems as $item)
<li class="{{ Active::route($item['route']) ? 'active' : '' }}">
<a href="{{ route($item['route']) }}">{{ $item['name'] }}</a>
</li>
@endforeach
Partial Matches (Prefixes):
Use Active::prefix('admin.') to highlight routes under a prefix:
<li class="{{ Active::prefix('admin.') ? 'active' : '' }}">
Admin Panel
</li>
Facade vs. Helper:
Prefer the Active facade for readability in Blade:
{{ Active::route('home') ? 'text-blue-500' : '' }}
(Avoid direct class instantiation unless extending functionality.)
Blade Directives: Create a custom directive for cleaner syntax:
// In a service provider
Blade::directive('active', function ($expression) {
return "<?php echo \\Active::route({$expression}) ? 'active' : ''; ?>";
});
Usage:
<li class="@active('dashboard')">...</li>
View Composers: Pass active state logic to views via composers:
public function compose($view) {
$view->with('isDashboard', Active::route('dashboard'));
}
JavaScript Integration: Use the active state to trigger JS logic (e.g., tab switching):
if (document.querySelector('.active').dataset.route === 'settings') {
loadSettingsTab();
}
Multi-Level Menus: Combine with nested Blade loops for hierarchical menus:
@if(Active::prefix('admin.'))
<ul class="submenu">
@foreach($adminRoutes as $route)
<li class="{{ Active::route($route) ? 'active' : '' }}">
<a href="{{ route($route) }}">{{ $route }}</a>
</li>
@endforeach
</ul>
@endif
Route Caching:
php artisan route:cache), clear it after adding new routes to avoid stale active states.php artisan route:clear in development.Case Sensitivity:
dashboard vs. Dashboard).Middleware Interference:
auth) may not trigger active states if the user isn’t authenticated. Test edge cases.Dynamic Routes:
posts.show, {post}) won’t match unless the exact name is provided. Use Active::route('posts.show', $post->id) if needed (requires custom logic).Facade Availability:
Active facade is only available after the service provider is registered. Avoid using it in AppServiceProvider boot methods.Check Current Route: Dump the current route name for debugging:
dd(Route::current()->getName());
Verify Config:
Ensure config/activemenu.php hasn’t been overridden with an empty class value.
Test with Hardcoded Values: Temporarily hardcode the active class to isolate issues:
<li class="{{ 'active' }}">...</li>
(If the style applies, the issue is with Active::route() logic.)
Custom Matching Logic: Extend the package by creating a decorator:
class CustomActive extends \Juy\ActiveMenu\Active {
public function isCurrent($routes) {
// Add custom logic (e.g., check URL segments)
return parent::isCurrent($routes) || str_contains(request()->path(), 'custom-path');
}
}
Bind it in a service provider:
$this->app->bind('Active', function () {
return new CustomActive();
});
Multiple Active Classes: Modify the config to support multiple classes:
'classes' => [
'active' => 'default-active',
'nested' => 'nested-active',
],
(Requires updating the package source or creating a wrapper.)
Laravel 8+ Compatibility: Override the service provider to support newer Laravel versions:
public function register() {
if (! $this->app->has('Active')) {
$this->app->singleton('Active', function () {
return new \Juy\ActiveMenu\Active();
});
}
}
Vue/React Integration: Pass active state via API or props:
// Vue example
data() {
return {
isActive: {!! json_encode(Active::route('dashboard')) !!}
};
}
Route::current() in PHPUnit to mock active states:
Route::current(function () {
return Route::getRoutes()->getByName('dashboard');
});
<li class="{{ Active::route('dashboard') ? 'text-blue-500 dark:text-blue-400' : '' }}">
@if(Active::route('dashboard'))
<button onclick="changeLanguage('en')">English</button>
@endif
How can I help you explore Laravel packages today?