robertboes/inertia-breadcrumbs
A Laravel package for defining and sharing breadcrumbs with Inertia.js. Set up trails in routes or controllers, then render them in your Vue, React or Svelte pages as props, with a clean, flexible API and support for nested navigation.
robertboes/inertia-breadcrumbs gives you a request-scoped breadcrumb store that is shared with your Inertia responses, so page components can render a trail without each controller manually building props.
Minimal setup
composer require robertboes/inertia-breadcrumbs
The package is auto-discovered; there is typically no required config publish for a first use case. Confirm the shared prop name and middleware behaviour by checking the package README and, if present, config/inertia-breadcrumbs.php.
First use case — add crumbs before rendering
use RobertBoes\InertiaBreadcrumbs\Breadcrumbs;
public function show(User $user)
{
Breadcrumbs::add('Users', route('users.index'));
Breadcrumbs::add($user->name, route('users.show', $user));
return Inertia::render('Users/Show', [
'user' => $user,
]);
}
Then consume the shared breadcrumbs prop in your persistent layout:
<script setup>
import { Link, usePage } from '@inertiajs/vue3'
const { breadcrumbs } = usePage().props
</script>
<template>
<nav aria-label="Breadcrumb">
<Link v-for="crumb in breadcrumbs" :key="crumb.url" :href="crumb.url">
{{ crumb.title }}
</Link>
</nav>
</template>
Where to look first
RobertBoes\InertiaBreadcrumbs\Breadcrumbs — the primary API surface.Controller-level trails for CRUD pages
Define crumbs immediately before returning the Inertia response. This keeps the trail close to the route/action that owns the page and avoids hidden global state.
public function index()
{
Breadcrumbs::add('Users', route('users.index'));
return Inertia::render('Users/Index');
}
public function edit(User $user)
{
Breadcrumbs::add('Users', route('users.index'));
Breadcrumbs::add($user->name, route('users.show', $user));
Breadcrumbs::add('Edit');
return Inertia::render('Users/Edit', compact('user'));
}
Base crumbs via middleware
For trails that always start with “Home” or “Dashboard”, add the root crumb in a middleware or in HandleInertiaRequests::share() before the controller runs. Be deliberate about ordering: middleware-added crumbs should appear before controller-added crumbs.
public function handle(Request $request, Closure $next): Response
{
Breadcrumbs::add('Home', route('dashboard'));
return $next($request);
}
Route-name driven maps
For larger apps, map route names to titles in a config array and resolve crumbs in a listener/middleware. This is useful for static sections (Settings → Profile, Billing → Invoices), while controllers handle dynamic resource names.
$titles = [
'settings.profile' => 'Profile',
'settings.billing' => 'Billing',
];
Rendering and accessibility
aria-current="page" to the last item.Testing
Inertia’s testing helpers make breadcrumb assertions cheap:
$response->assertInertia(fn (Assert $page) => $page
->component('Users/Show')
->has('breadcrumbs', 2)
->where('breadcrumbs.1.title', $user->name)
);
This catches accidental omission when a controller returns early or uses a different response path.
Laravel Boost integration (1.2.0)
If your team uses Laravel Boost, refresh the generated guidelines after upgrading:
composer update robertboes/inertia-breadcrumbs
php artisan boost:update
The new guideline/skill gives AI tooling accurate information about the package’s API, which reduces hallucinated helper names during code generation.
Per-request state and Octane
The breadcrumb store is request-scoped. Under Octane or other long-lived workers, verify the package resets state between requests. If you see crumbs leaking from one request into another, check whether the store is registered as a singleton and whether a reset/forget mechanism is needed.
Ordering is your responsibility
Crumbs are appended in call order. Add parents before children. If a middleware adds “Home” after the controller has already added “Users”, the trail will be backwards.
Don’t link the current page
The final crumb usually represents the current page. Pass only a title (no URL) for it, or handle the last item specially in the layout.
Middleware and response path coverage
Crumbs only appear if they are added before the Inertia response is rendered. Watch for:
back() paths.Inertia::render() from a service class.Prop collisions
The shared prop is commonly named breadcrumbs. If your page already passes a breadcrumbs prop, one will overwrite the other. Rename your local prop or customise the package prop name if supported by config.
Partial reloads
With Inertia partial reloads, closures in HandleInertiaRequests::share() may not be evaluated the same way as full visits. Verify breadcrumbs are present when a page is refreshed with only: [...]; if not, add crumbs in the controller rather than relying solely on shared closures.
Debugging
$response->viewData('page')['props']['breadcrumbs']) in a test.dd(Breadcrumbs::toArray()) before rendering if the prop is empty.bootstrap/app.php or Kernel.php — especially the Inertia middleware.Upgrade note for 1.2.0
1.2.0 is additive: it adds Laravel Boost AI guidelines/skills and does not change runtime behaviour. No application code changes or migrations are required when upgrading from 1.1.0. After upgrading, rerun your Boost install/update command if you rely on AI-generated code, and commit the refreshed guideline files if your team tracks them.
How can I help you explore Laravel packages today?