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

Breadcrumbs Laravel Package

arcanedev/breadcrumbs

ArcaneDev Breadcrumbs is a Laravel package for defining and rendering flexible breadcrumb trails. Build crumbs from routes, closures, or arrays, customize templates, and output accessible navigation with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Check the install gate before you write any code. The latest tagged release is from November 2020, so its composer.json almost certainly pins illuminate/support/illuminate/routing to Laravel 6–8. On a modern Laravel you will get a dependency-resolution failure, not a runtime bug. Confirm with:

composer require arcanedev/breadcrumbs --dry-run

If it refuses, stop and decide between a fork with widened constraints (see Gotchas) and a maintained alternative (diglactic/laravel-breadcrumbs is the closest named-trail equivalent) before you build conventions on top of this API.

Once it resolves, the first read is three files in the vendor tree:

  • src/BreadcrumbsServiceProvider.php — what is auto-discovered, what config/views are published, whether a Blade directive is registered.
  • src/Breadcrumbs.php — the fluent surface (push, pushFromRoute, pushFromAction, render).
  • resources/views/*.blade.php + config/breadcrumbs.php — the view and name/separator keys you will actually override.

Publish so you own the template and config:

php artisan vendor:publish --provider="Arcanedev\Breadcrumbs\BreadcrumbsServiceProvider"

First use case — a three-level trail in a controller, rendered in the layout:

use Arcanedev\Breadcrumbs\Facades\Breadcrumbs;

public function show(User $user)
{
    Breadcrumbs::push('Home', route('home'));
    Breadcrumbs::push('Users', route('users.index'));
    Breadcrumbs::push($user->name);          // no URL => current page
}
{{-- layouts/app.blade.php --}}
{!! Breadcrumbs::render() !!}

Get that rendering, then immediately move the definition out of the controller (next section) — controllers should not own navigation.

Implementation Patterns

Route-keyed trail map + middleware (the pattern worth adopting). Because this package is a linear chain you push onto, not named trails, the cleanest day-to-day structure is a single declarative map keyed by route name, applied by one middleware. Controllers and views stay untouched, and adding a page means adding four lines of config.

// config/breadcrumbs-map.php
return [
    'users.index' => [
        ['route' => 'home', 'title' => 'Home'],
        ['route' => 'users.index', 'title' => 'Users'],
    ],
    'users.show' => [
        ['route' => 'home', 'title' => 'Home'],
        ['route' => 'users.index', 'title' => 'Users'],
        ['route' => 'users.show', 'title' => fn ($user) => $user->name],
    ],
];

Derive from the route, don't hardcode URLs. pushFromRoute() resolves through Laravel's URL generator, so route model binding, localized slugs, and tenant domains all keep working:

Breadcrumbs::pushFromRoute('users.index', [], 'Users');
Breadcrumbs::pushFromRoute('users.show', [$user], $user->name);

Build once, in one place. Pick exactly one of: a middleware, a View::composer on your layout, or a base-controller trait. Never two — the service is a stateful singleton and you will get duplicated crumbs.

Translate titles at the boundary, not in the view: Breadcrumbs::push(__('nav.users'), route('users.index')).

Custom template — copy the published view into resources/views/vendor/breadcrumbs/ and switch config('breadcrumbs.view'). This is your hook for Tailwind classes, wrapping <nav aria-label="Breadcrumb">, or a <ol> with microdata.

Emit JSON-LD from the same trail so the visible navigation and the SEO markup can never diverge:

$items = collect(Breadcrumbs::render()->???);

If the trail isn't exposed as an array, keep the trail definition in a small BreadcrumbTrail support class that both the facade call and the JSON-LD builder consume.

Testing. Assert on the rendered page, not on package internals: $this->get('/users/1')->assertSeeInOrder(['Home', 'Users', 'Jane']). Add one characterization test per distinct trail shape; that test is what catches behavioural drift on any future upgrade.

Gotchas and Tips

  • Version wall, not a bug. A 2020 release will not install on Laravel 9+ without intervention. Widening constraints in a fork ("illuminate/support": "^6|^7|^8|^9|^10|^11") usually "just works" because the API touches only the URL generator and the view factory — but that is a fork you now maintain, and you must re-run your breadcrumb characterization tests on each Laravel major. Budget it, or pick the maintained alternative.
  • Stateful singleton. The trail accumulates on the resolved instance for the whole request. Rendering twice (layout + a component) prints the trail twice; in tests, two requests in one test case can leak crumbs. Build in one place, and check Breadcrumbs.php for a reset/flush method before you rely on re-builds.
  • pushFromRoute() throws. Unknown route names or missing required parameters raise RouteNotFoundException / UrlGenerationException — a 500 on a page whose only crime is a broken nav. Guard with Route::has() when the map is data-driven, or wrap in try/catch and degrade to a title-only crumb.
  • The last crumb must have no URL, otherwise you render a link pointing at the page you're on. Keep that convention in the map (omit route on the terminal item) and enforce it in the custom view.
  • Escaping. The shipped views interpolate the pre-rendered HTML, so check whether titles are escaped there. If you feed model names or user input into push() without escaping in the template, you have an XSS vector on every page. Escape at push time or fix the view — and write a test with <script> in a model name.
  • Cache interaction. If you use full-page or response caching, the trail is baked into the HTML. Fine for static pages, wrong the moment a crumb contains a user name or a tenant-specific path.
  • Config quirks. view and the separator/name keys are read at render time, so config(['breadcrumbs.view' => ...]) mid-request works for per-section layouts — but keep it to one convention or the nav becomes inconsistent between screens.
  • No named trails = no reuse. Unlike diglactic/laravel-breadcrumbs, you cannot define a trail once and render it from several pages; every page pushes its own chain. That's why the route map above matters — without it, breadcrumb definition scatters across controllers and rots.
  • Extension points are exactly two: the view (safe, upgrade-friendly) and the facade's fluent methods via a wrapper class (your app's seam). Do not subclass Breadcrumbs — you'll be patching the vendor tree.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager