Requirements
- PHP: 8.2, 8.3, 8.4
- Laravel: 10.x, 11.x, 12.x (Illuminate Support/View/Routing)
Installation
composer require milenmk/laravel-route-label
No further setup is needed (package discovery enabled) for basic usage.
Quick Start
1) Define routes with labels
use Illuminate\Support\Facades\Route;
// Simple string label
Route::get('/users', [UserController::class, 'index'])
->name('users.index')
->label('Users');
// Dynamic label via closure
Route::get('/users/{user}/edit', [UserController::class, 'edit'])
->name('users.edit')
->label(fn($params) => "Edit {$params['user']->name}");
// Translation key
Route::get('/home', [HomeController::class, 'index'])
->name('home')
->label('trans:routes.home');
// String-backed Enum
enum RouteLabel: string { case Users = 'Users'; }
Route::get('/users', [UserController::class, 'index'])
->name('users.index')
->label(RouteLabel::Users);
You must call ->name() before ->label().
2) Use the label in Blade
Using the helper
<a href="{{ route('users.index') }}">{{ routeLabel('users.index') }}</a>
<a href="{{ route('users.edit', ['user' => $user]) }}">{{ routeLabel('users.edit', ['user' => $user]) }}</a>
Renders
<a href="/users">Users</a>
<a href="/users/1/edit">Edit John</a>
Using Blade directives
-
Simple directive
@routeLink('users.index')
Renders:
<a href="/users">Users</a>
-
With additional attributes
@routeLink('users.index', ['class' => 'btn btn-primary', 'wire:navigate' => true])
Renders:
<a href="/users" class="btn btn-primary" wire:navigate>Users</a>
-
With Alpine.js / complex attributes
@routeLink('users.index', [
'class' => 'menu-item',
'x-data' => '{ open: false }',
'x-show' => 'open',
'@click' => 'open = !open'
])
Renders:
<a href="/users" class="menu-item" x-data="{ open: false }" x-show="open" @click="open = !open">Users</a>
Block directives for complex content
@routeLinkStart('home', ['class' => 'logo-link', 'wire:navigate' => true])
<img class="logo" src="{{ asset('images/logo.png') }}" alt="Logo" />
<span class="brand-name">{{ config('app.name') }}</span>
@routeLinkEnd
Renders
<a href="/" class="logo-link" wire:navigate>
<img class="logo" src="/images/logo.png" alt="Logo" />
<span class="brand-name">My App</span>
</a>
Another example with Alpine.js
@routeLinkStart('profile', [
'class' => 'profile-link',
'x-data' => '{ open: false }',
'@click' => 'open = !open'
])
<img class="avatar" src="{{ $user->avatar }}" alt="Profile" />
<span class="name">{{ $user->name }}</span>
<svg class="dropdown-icon" :class="open ? 'rotate-180' : ''">...</svg>
@routeLinkEnd
Renders
<a href="/profile" class="profile-link" x-data="{ open: false }" @click="open = !open">
<img class="avatar" src="/avatar.jpg" alt="Profile" />
<span class="name">John Doe</span>
<svg class="dropdown-icon">...</svg>
</a>
3) Using the Blade component
<x-route-link route="users.index" class="btn btn-primary" />
<x-route-link route="users.edit" :params="['user' => $user]" />
<x-route-link route="home" />
<x-route-link route="users.index" :attributes="['wire:navigate' => true]" />
Renders
<a href="/users" class="btn btn-primary">Users</a>
<a href="/users/1/edit" class="text-blue-500 hover:underline">Edit John</a>
<a href="/" class="text-blue-500 hover:underline">Homepage</a>
<a href="/users" class="text-blue-500 hover:underline" wire:navigate>Users</a>
Boolean attributes (like wire:navigate) are added as attribute names only when set to true.
HTML is escaped by default, configurable via config/route-label.php.
Fallbacks: if a route has no label, the route name is used (missing_label_behavior).