Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Easynav Laravel Package

devmarketer/easynav

EasyNav is a lightweight Laravel package for building navigation menus without repetitive markup. Define menus in PHP, render them in Blade, and handle active states and nested links through a simple API—ideal for adding consistent navbars and sidebars to Laravel apps.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install it with Composer:

    composer require devmarketer/easynav
    
  2. Laravel 5.5+ discovers the service provider automatically. On older versions, register DevMarketer\EasyNav\EasyNavServiceProvider in config/app.php and add the EasyNav facade alias under aliases.

  3. Check whether the package publishes configuration with php artisan vendor:publish — anything it exposes will land in config/easynav.php. Read the README first; the package is small enough that src/ (service provider, facade, and a single helper class) is the whole implementation.

  4. The first use case is almost always a single nav link that needs an active class:

    {{-- resources/views/partials/nav.blade.php --}}
    <li class="{{ EasyNav::isActive('home') ? 'active' : '' }}">
        <a href="{{ route('home') }}">Home</a>
    </li>
    
    <li class="{{ EasyNav::isActive('admin.*') ? 'active' : '' }}">
        <a href="{{ route('admin.dashboard') }}">Admin</a>
    </li>
    

    isActive() compares the current route name against the string you pass and supports * wildcards, so admin.* lights the parent item up across an entire section without you writing conditionals for every child route.

Implementation Patterns

Drive the nav from data, not from markup. The highest-leverage pattern is a menu array plus one @foreach partial. Keep the pattern (admin.*, posts.show) next to the label and URL:

// config/navigation.php
return [
    ['pattern' => 'home',        'label' => 'Home',  'route' => 'home'],
    ['pattern' => 'posts.*',    'label' => 'Blog',  'route' => 'posts.index'],
    ['pattern' => 'admin.*',    'label' => 'Admin', 'route' => 'admin.dashboard'],
];
@foreach (config('navigation') as $item)
    <li class="{{ EasyNav::isActive($item['pattern']) ? 'active' : '' }}">
        <a href="{{ route($item['route']) }}">{{ $item['label'] }}</a>
    </li>
@endforeach

This is the point where the package pays off: adding a section is a one-line config change, and you never touch the Blade file again.

Section highlight vs. exact highlight. Use a wildcard (admin.*) on the top-level menu item so it stays highlighted on every child page, and an exact route name on the sub-item. Mixing the two in the same list is fine as long as the patterns are specific.

Multiple alternatives. Pass an array when several unrelated routes belong to the same tab, e.g. EasyNav::isActive(['login', 'register', 'password.*']) for an "Account" entry.

URL matching for non-named links. Static pages or legacy links without a route name need URL comparison rather than route-name comparison — keep those entries separate in your menu config so you don't accidentally compare a route name against a path.

Wrap it once. If you find yourself writing EasyNav::isActive(...) ? 'active' : '' more than twice, add a tiny Blade component or a @class call in support. The package gives you a boolean; the ternary is yours to centralize.

Dropdowns and open state. The same boolean that toggles active should toggle show on Bootstrap dropdowns and aria-expanded, otherwise the section highlight and the open dropdown disagree.

Gotchas and Tips

You may not need it. Modern Laravel ships request()->routeIs('admin.*'), which does the same wildcard route-name comparison with no dependency. If you're on Laravel 8+, benchmark EasyNav against that before adding it — its value is mostly ergonomics and a slightly nicer API.

It's a legacy package. 105 stars, zero dependents, low maintenance activity. Check the composer.json illuminate/support constraint against your Laravel version before committing; if there's a conflict, don't force it with --ignore-platform-reqs, just use routeIs() or fork the ~200 lines.

Wildcard depth is the classic surprise. admin.* matching admin.users.edit depends on whether the implementation uses Str::is (matches across dots) or a single-segment regex. Verify with a quick dd(EasyNav::isActive('admin.*')) on a deeply nested route before rolling it out to a full menu.

Route parameters are ignored. posts.show returns true for every post — usually desired for menu highlighting, but if you need to know which post, compare request()->route('post') yourself.

URL comparisons and trailing slashes. If you use the URL-matching path, /admin and /admin/ and /admin?page=2 are three different strings. Normalize before comparing, or you'll get links that mysteriously never highlight.

Config cache will bite you. Menu arrays defined in config are baked in by php artisan config:cache. Run php artisan config:clear while iterating on the navigation structure, or you'll spend ten minutes wondering why your new menu item doesn't appear.

Don't cache the rendered partial. View-fragment or response caching a nav partial freezes the active class on whichever page warmed the cache. Cache the menu data, never the rendered HTML.

Localised route names. If you're using translated route names (route('home', [], false) patterns or per-locale naming), the pattern string in your menu config has to match the actual registered name in the current locale.

Testing. isActive() reads the current request, so set the route first ($this->get(route('admin.dashboard'))) and then assert the rendered HTML contains class="active". Testing the helper in isolation requires binding a fake request.

Extension points are thin. There's essentially the facade and one helper class. If you need custom matching (subdomain-aware, permission-aware, "always active" items), the cleanest path is binding your own implementation in a service provider rather than patching the vendor directory — the package is small enough to copy into app/Support/ if it becomes load-bearing.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core