Using Route Names Instead of URLs
In Laravel, I prefer using route names instead of URLs for making UI state decisions. Unlike URLs, route names offer more stability as they are not affected by variables like parameters, query strings, and hashes. By relying on route names, we can ensure consistent and reliable comparisons.
You can name a route like so:
use Illuminate\Support\Facades\Route;
Route::view('/about', 'about')->name('about');
So how do you actually retrieve this when you're building your UI?
There are three (reasonable) ways to fetch the current route name that Laravel supports:
// Will return either the current route name
// or `null`, if there isn't one
$route = Route::current()->getName();
// Shorthand for the code above, internally Laravel
// will simply call Route::current()->getName()
$route = Route::currentRouteName();
// Via the global `request` helper
$route = request()->route()->getName();
Any of these boil down to the same internal code in Laravel, what you choose is simply your preferred flavour.
Checking the Current Active Route
This functionality is commonly required in UI elements such as the header or navigation, where it becomes essential to determine the active route in order to highlight the corresponding link.
Here's an example I've recently worked on using the TALL stack:
<div class="flex justify-between pb-10">
<a class="text-forest underline" href="/">about</a>
<a class="text-forest underline" href="/shop">shop</a>
<a class="text-forest underline" href="/contact">contact</a>
</div>
Above we have a basic header, and we want to change it so that those underline
classes only apply when the link in the header is the active one for the user.
We could do that by making a simple check using the route name code we saw above:
<div class="flex justify-between pb-10">
<a @class(['text-forest ', 'underline' => Route::currentRouteName() === 'about']) href="/">about</a>
<a @class(['text-forest ', 'underline' => Route::currentRouteName() === 'shop']) href="/shop">shop</a>
<a @class(['text-forest ', 'underline' => Route::currentRouteName() === 'contact']) href="/contact">contact</a>
</div>
Works! Pretty simple and easy to understand.
Using the "is" Method for More Fluent Code
There's an improvement we can make however. Laravel has some built in route checking functionality that we can leverage to make this code simpler.
The Route::is()
method can check if the string you provide matches the name of the active route. Let's give it a try.
<div class="flex justify-between pb-10">
<a @class(['text-forest ', 'underline' => Route::is('about')]) href="/">about</a>
<a @class(['text-forest ', 'underline' => Route::is('shop')]) href="/shop">shop</a>
<a @class(['text-forest ', 'underline' => Route::is('contact')]) href="/contact">contact</a>
</div>
Much more concise, and super quick to take in at a glance. This is what Laravel is great at.
In my example, there was one final scenario that I needed to support. The client wanted the shop
link to be underlined whenever the user was on a few different routes. This meant we needed to check if our active route matched one of many names. Luckily, Laravel's is
method also supports this.
You can provide a regular expression to the Route::is
method:
<div class="flex justify-between pb-10">
<a @class(['text-forest ', 'underline' => Route::is('product.*')]) href="/shop">shop</a>
</div>
// web.php
Route::name('product.index')->get('/shop', Index::class);
Route::name('product.show')->get('/product/{slug}', Show::class);
Now, the underline
class will be applied when any route name, starting with product.
is active. In the routes above, you can see that both route names start with product.
, meaning despite the inconsistency in URL structure - /shop
vs /product/*
, they will both match.
No comments yet…