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

watson/breadcrumbs

Lightweight Laravel package for defining and rendering breadcrumb trails. Add breadcrumbs in PHP, attach them to routes, and output accessible HTML with Blade. Supports current-page detection, custom templates, nested trails, and simple configuration for Laravel applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package with Composer:

composer require watson/breadcrumbs

On Laravel 5.5+ the Watson\Breadcrumbs\ServiceProvider and the Breadcrumbs facade are auto-discovered. If you are on an older version, register the provider in config/app.php and add the alias:

'Breadcrumbs' => Watson\Breadcrumbs\Facades\Breadcrumbs::class,

Publish the config so you can point the package at your own view (the default is a Bootstrap-flavoured breadcrumbs::breadcrumbs template):

php artisan vendor:publish --provider="Watson\Breadcrumbs\ServiceProvider"

The first use case is almost always a controller method or a view composer that pushes a trail and then renders it in your layout:

use Watson\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/active crumb

    return view('users.show', compact('user'));
}
{{-- layouts/app.blade.php --}}
{!! Breadcrumbs::render() !!}

Start by reading src/Breadcrumbs.php (it is tiny — push, render, clear, and the crumb array) and the published config/breadcrumbs.php. That is the entire surface area; there is no route-scanning magic to learn.

Implementation Patterns

Centralise the trail per resource in a view composer. Rather than scattering push() calls through controllers, bind a composer in a service provider and switch on the route name:

View::composer('layouts.app', function ($view) {
    $crumbs = Breadcrumbs::forRoute(request()->route());
    // or, using the package directly:
    Breadcrumbs::push('Home', route('home'));

    if (request()->routeIs('users.*')) {
        Breadcrumbs::push('Users', route('users.index'));
    }
});

This keeps every controller free of presentation logic and gives you one place to change the hierarchy.

Use the fluent return value. push() returns the breadcrumb instance, so you can build a chain in one expression:

Breadcrumbs::push('Home', '/')
    ->push('Blog', route('posts.index'))
    ->push($post->title);

Traverse a model's ancestry. For category trees or threaded comments, walk the parent chain in a loop and push as you go (reversing first so the trail reads root → leaf):

$ancestors = $category->ancestors()->reverse();
foreach ($ancestors as $ancestor) {
    Breadcrumbs::push($ancestor->name, route('categories.show', $ancestor));
}
Breadcrumbs::push($category->name);

Wrap it in a Blade component so your templates stay declarative and you can swap the package later without touching views:

<x-breadcrumbs :items="Breadcrumbs::toArray()" />

Assert on output in feature tests — it is a cheap regression guard on your navigation:

$this->get('/users/1')
    ->assertSeeInOrder(['Home', 'Users', 'Taylor']);

Gotchas and Tips

  • The instance is a singleton, so crumbs persist for the request. If you reuse the same application instance across tests, Octane workers, or long-running jobs, call Breadcrumbs::clear() (or re-bind the instance) at the start of each request. A RefreshBreadcrumbs middleware or a before hook in your composer is the cleanest fix.
  • render() returns HTML. Use {!! !!} rather than {{ }}, and make sure your custom view escapes the titles with e() — user-supplied model names in a crumb are an XSS vector otherwise.
  • A crumb with no URL is your "current page." Use that (rather than a separate active flag) to render plain text instead of an anchor; check the view's $crumb['url'] === null handling when you customise the template.
  • Always build URLs with route()/url(), never string concatenation. It keeps the trail correct when you add locale prefixes, subdomain routing, or change a URI; hardcoded /users/1 breadcrumbs silently rot.
  • The package does not generate breadcrumbs. Unlike route-based generators, there is no convention to lean on — if the trail is wrong it is because your composer logic is wrong. dd(Breadcrumbs::toArray()) at the top of the layout is the fastest debug.
  • Config quirks are minimal: the only knob worth changing day-to-day is view. Publish it, point it at breadcrumbs.app in your own resources/views/components and you fully control markup, separators, and microdata/JSON-LD.
  • Version compatibility: the package is small and stable but old. On Laravel 10/11 you may need to relax the illuminate/support constraint in a fork, or accept that it is ~100 lines you could vendor into app/Support/Breadcrumbs.php — worth considering given there are zero dependents and no recent activity.
  • Extension points are just the facade and the view. If you need conditional crumbs (push only when a section is visible) or caching, do it in your composer; there is no event system to hook into.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons