kodicomponents/navigation
KodiComponents Navigation is a Laravel package for defining and rendering site navigation menus in code. It helps organize links, nested items, active states, and Blade output, making menus consistent and easier to maintain across an application.
Because the repository is unavailable and there is no public documentation, treat the installed source as the spec. Start there, not with blog posts.
composer require kodicomponents/navigation and check Packagist first — with an unknown repo you cannot assume the vendor is still reachable. If it is not on Packagist, add a repositories VCS entry pointing at the fork you control, and pin a commit.vendor/kodicomponents/navigation/composer.json and look for extra.laravel.providers / aliases. If present, discovery handles registration; if not, add the provider and facade manually in config/app.php. Then read the service provider — it tells you whether the nav is a singleton, what it binds, and whether a Blade directive or config file is published.Navigation/Nav with fluent add()/item() methods and a render() or toArray(). The shipped tests, if any, are the most reliable API reference — read them before writing application code.layouts/app.blade.php. Get a two-item menu (Home, Dashboard) rendering before you add active states or authorization.Version reality check before you invest: last release was September 2020, which predates Laravel 9. Test composer require against your actual framework version early — a ^7.0|^8.0 constraint will block install on 10/11 and you will need --ignore-platform-reqs or a fork with widened constraints.
Register menus centrally, render locally. Define the menu graph in a dedicated NavigationServiceProvider (not AppServiceProvider, which gets crowded) and keep views dumb. This gives you one place to audit links and one place to change when routes move.
// app/Providers/NavigationServiceProvider.php
public function boot(): void
{
Nav::make('main', function ($nav) {
$nav->add('Home', route('home'));
$nav->add('Dashboard', route('dashboard'))->visible(fn () => auth()->check());
$nav->add('Admin', route('admin.index'))->visible(fn () => Gate::allows('admin'));
});
}
Resolve labels at render time, not registration time. Call __('nav.home') inside the render/closure path rather than passing a translated string to add(). If you translate at registration and the user switches locale mid-session, the menu stays in the old language.
Active state. Most packages of this vintage infer "active" by comparing the item URL to request()->url(), which breaks on parameterised routes. Prefer an explicit route-name API if one exists (->route('users.*') or ->activeWhen('users.*')); otherwise set active flags yourself in a view composer using request()->routeIs().
Multiple menus, one builder. Use named menus (main, sidebar, footer) rather than one global mutable instance — a singleton menu that every provider appends to becomes order-dependent and impossible to test in isolation.
Authorization. Gate the additions rather than the rendering: an item that never enters the menu cannot leak through a forgotten @can in a template. Combine with visible() closures where the package supports them, but keep a Blade-level guard as the backstop.
Composition with view composers. If items depend on per-request data (current team, unread count), build in a view composer bound to the layout rather than in a global provider, so the menu is built after the request context is known.
Menu interface so you can swap in spatie/laravel-navigation or a plain view composer without touching templates.{!! !!} around a cached menu is a stored-XSS vector.Cache::remember), any visible/href closure will fail or silently evaluate once and freeze. Cache only the resolved array form, or cache the underlying data and rebuild the nav each request.render() simply will not appear. This bites hardest when a controller adds a breadcrumb-style item after the view has begun composing. Establish "menus are complete before the layout renders" as a rule and enforce it in a test./admin when you are on /admin/users, and exact matching misses it. Write one feature test per menu item asserting active/inactive on two routes; this is the single highest-value test for any nav package.config/app.php has a static provider list or you run with discovery disabled, the facade alias will be missing and you will get a "class not found" that looks like an install failure. Register manually and move on.dd(Nav::make('main')->toArray()) before touching Blade. If the menu looks empty in the browser but populated in tinker, the problem is render order or a cached compiled view, not the package.Macroable on the nav class first — a macro is a cleaner extension than subclassing. Failing that, bind your own subclass in the container over the package's binding, and keep that override in one provider so upgrades are a one-line diff.How can I help you explore Laravel packages today?