Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jason's avatar

Best practice for handling "active" menu item in L5

I've been trying to wrap my head around how best to address marking a menu item as the current page (I'm using twitter bootstrap for front-end css). In L4 it is suggested to do something like this:

<li class="{{ Request::is('home') ? 'class="active"' : '' }}"><a href="{{URL::to('clients')}}">Home</a></li>

This doesn't seem to work in L5 though.

In attempt to stay DRY, I implemented a Nav helper class with the following method:

    public static function setActive($path, $request, $active = 'active')
    {
        return $request->is($path) ? $active : '';
    }

in my blade template I can do this:

<li class="{{\Webapp\Helpers\Nav::setActive('home', $request)}}">

but I will have to return the request in my controllers for every route that I want to enable for active menu navigation:

return view('home', compact('request'));

I swear I saw a laracast that touched on this subject but am having trouble finding it again.

Is returning the request in every controller method the best way to handle active menu items? Is there a more elegant solution?

EDIT: found the laracast I was looking for but would still like to get feedback from others on solutions that work well in L5:

https://laracasts.com/lessons/active-states

0 likes
39 replies
DaRo's avatar

This is really old, but i've found a solution that worked for me:

I did the menu list in bootstrap way, and it would be like this;

<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">

<li {{{ (Request::is('dashboard') ? 'class=active' : '') }}}>
<a href="{{action('action to see the view')}}">Home</a>
</li>

<li {{{ (Request::is('companies') ? 'class=active' : '') }}}>
<a href="{{action('action to see the view')}}">Companies</a>
</li>
</ul>

</div><!--/.nav-collapse -->

Notist that the thing that you put inside the request should be the path, in my case, for the dasboard was project.dev/dashboard

Hope this helps someone.

28 likes
bestmomo's avatar

I've created 2 helpers :

if (!function_exists('classActivePath')) {
    function classActivePath($path)
    {
        return Request::is($path) ? ' class="active"' : '';
    }
}

if (!function_exists('classActiveSegment')) {
    function classActiveSegment($segment, $value)
    {
        if(!is_array($value)) {
            return Request::segment($segment) == $value ? ' class="active"' : '';
        }
        foreach ($value as $v) {
            if(Request::segment($segment) == $v) return ' class="active"';
        }
        return '';
    }
}

And I use it as this :

<li {!! classActivePath('medias') !!}>
    <a href="{!! route('medias') !!}"><span class="fa fa-fw fa-file-image-o"></span> {{ trans('back/admin.medias') }}</a>
</li>
<li {!! classActiveSegment(1, 'blog') !!}>
    <a href="#" data-toggle="collapse" data-target="#articlemenu"><span class="fa fa-fw fa-pencil"></span> {{   
    ...
</li>
3 likes
mindthebrand's avatar

It is more versatile.

if (!function_exists('classActivePath')) {
    function classActivePath($path)
    {
        $path = explode('.', $path);
        $segment = 1;
        foreach($path as $p) {
            if((request()->segment($segment) == $p) == false) {
                return '';
            }
            $segment++;
        }
        return ' active';
    }
}
 <ul>
    <li class="{!! classActivePath('order') !!}">
        <a href="#">Order</a>
        <ul>
            <li class="{!! classActivePath('order.index') !!}">
                <a href="{{ route('order.index') }}"> Orders</a>
            </li>
            <li class="{!! classActivePath('order.index') !!}">
                <a href="{{ route('order.create') }}"> Order Create</a>
            </li>
        </ul>
    </li>
</ul>  
4 likes
pmall's avatar

I send $request->segment(1) through a view composer as an $active variable.

Then <li class="{ { $active == 'posts' ? 'active' : '' } }">posts</li>.

1 like
JoshWegener's avatar

What I decided to go with....

if (!function_exists('menuActiveRoute')) {
    function menuActiveRoute($routeName, $includeClass = true, $className = 'active') {
        return preg_match('/^' . preg_quote($routeName, '/') . '/', \Request::route()->getName()) ? ($includeClass ? "class=\"{$className}\"": $className): '';
    }
}

And a longer version if you prefer...

if (!function_exists('menuActiveRoute')) {
    function menuActiveRoute($routeName, $includeClass = true, $className = 'active') {
        $activeClass = ($includeClass ? "class=\"{$className}\"": $className);
        return preg_match('/^' . preg_quote($routeName, '/') . '/', \Request::route()->getName()) ? $activeClass: '';
    }
}
jjudge's avatar

I've seen this package used by a few demos, and and trying it out myself:

https://github.com/laravelista/Ekko

So far, it's working well, but it needs a wildcard or pattern match for the route name, for which I'm working on a PR.

Edit: Ekko now supports wildcard path names and multiple path names. This is absolutely essential for my use-case as some parts of my admin structure are four levels deep (since it models some real-life structures that need to be set up). This allows multiple sub-menus to activate the top-level menu that they are under. The wildcards then support resource-based URLs.

This is my top-level side-menu option for a "show", which lights up when any of about 30 pages under it are being used:

<li class="{{ Ekko::areActiveRoutes(['admin.shows.*', 'admin.shows.groups.*', 'admin.shows.groups.judges.*', 'admin.shows.products.*', 'admin.shows.orders.*']) }}">
    <a href="{{ route('admin.shows.index') }}">Shows</a>
</li>

My aims in choosing this were:

  • Not to reinvent this common requirement yet again. Yes, the 80% use-case might be quick and simple, but you will quickly hit limitations once your application becomes a little more complex.
  • Choose an open source package that gets most of the way and offer PRs to improve it to better fit my use-case (for both me and others in future projects).
  • To minimise PHP in the HTML markup - conditions, ternary operator etc. Just calling a function was the most I wanted to put into the markup.
  • To match against route names rather than paths. The path stays in routes.php in my applications and ALL other parts of the application just refer to route names. That way paths can be moved and juggled around as the application and its needs grow, without the need to find every instance that references a path.

On that last point, Ekko does support path matches too, so it's there if you want to use it.

6 likes
kel's avatar

I know this is old but here is what I did as a solution for me. This checks it by path and allows multiple paths as well as additional class pass through.

function active_class_path($paths, $classes = null)
{
    foreach ((array) $paths as $path) {
        if (request()->is($path)) {
            return 'class="' . ($classes ? $classes . ' ' : '') . 'active"';
        }
    }
    return $classes ? 'class="' . $classes . '"' : '';
}

And an example here

<ul class="menu">
    <li><a href="{{ url('articles') }}" {!! active_class_path(['articles', 'a/*']) !!}>Articles</a></li>
    <li><a href="{{ url('dashboard') }}" {!! active_class_path('dashboard', 'additional classes here') !!}>Dashboard</a></li>
    <li><a href="{{ url('dashboard/users') }}" {!! active_class_path('dashboard/users') !!}>Users</a></li>
    <li><a href="{{ url('dashboard/settings') }}" {!! active_class_path('dashboard/settings') !!}>Site settings</a></li>
</ul>
1 like
vipindasks's avatar

This is how I do it. In my controller I set a name and share it to the view

<?php namespace App\Http\Controllers\Admin;

use Auth;
use Validator;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;

class MyController extends Controller
{
    public function __construct()
    {
        View::share(['page_name_active'=> 'mypagename']);       
    }
    /* rest of logic */
}

And in my view, I check against the respective values and show active

                        <li class="@if($page_name_active=='mypagename')active @endif">
                            <a href="{{route('admin.mypage')}}" >My Page</a>
                        </li>
Gerard's avatar

Damn... I have this working

if (! function_exists('is_current_route')) {
    function is_current_route($route){
        return Request::url() == $route ? 'class=active' : '';
    }
}

but when I change it to Request::is it doesn't work anymore :S

if (! function_exists('is_current_route')) {
    function is_current_route($route){
        return Request::is($route) ? 'class=active' : '';
    }
}
1 like
somethingrandom's avatar

This is how I add active classes. I first create a functions file app/Helpers/functions.php and add this function:

    /* Set active class
    -------------------------------------------------------- */
    function set_active($path, $active = 'active') {
        return call_user_func_array('Request::is', (array)$path) ? $active : '';
    }

I then add this to autoload in composer.json

    "autoload": {
        "classmap": {...},
        "psr-4": {...},
        "files": [
            "app/Helpers/functions.php"
        ]
    },

Then run composer dumpautoload.

And then use the function like so:


    <ul>
        <li class="dropdown {{ set_active(['page', 'page/*']) }}">
            <a href="#" class="dropdown-toggle" data-toggle="dropdown">Page</a>
            <ul class="dropdown-menu" role="menu">
                <li class="{{ set_active(['page/child-1']) }}">
                    <a href="{{ url('page/child-1') }}">Child 1</a>
                </li>
                <li class="{{ set_active(['page/child-2']) }}">
                    <a href="{{ url('page/child-2') }}">Child 2</a>
                </li>
                <li class="{{ set_active(['page/child-3']) }}">
                    <a href="{{ url('page/child-3') }}">Child 3</a>
                </li>
            </ul>
        </li>
    </ul>

This will add the active class to .dropdown for the routes: /page and any child routes /page/*

e.g /page/child-1, /page/child-2, /page/child-3

and will also add the active class to each relevant child page.

2 likes
Khudadad's avatar

I 'm doing this like bellow : in my controller I declare $menu = '...'; and <$sub_menu = '....'; and check it in the views.

 <li class="<?php if ($menu == 'purchase') echo "active open dropdown"; ?>">
                                <a role="button" tabindex="0"><i class="fa fa-shopping-cart"></i> <span>Purchase Management</span> <span class="badge bg-lightred"></span></a>
                                <ul>
                                    <li class="<?php if ($sub_menu == 'purchase_list') echo "active"; ?>"><a href="/purchase"><i class="fa fa-caret-right"></i> Purchase List</a></li>
                                    <li class="<?php if ($sub_menu == 'add_new_purchase') echo "active"; ?>"><a href="/purchase/add" ><i class="fa fa-caret-right"></i> Add New Purchase</a></li>
                                </ul>
                            </li>
kickthemooon's avatar

I am solving it by passing variables from my controllers.

public function index(){
        $data=array('menuParent'=>'Users', 'menuChild'=>'viewUsers');
        $users=User::all();
        return view('admin.users.index', $data)->with(compact('users'));
    }

view

<li class="treeview @if(isset($menuParent)) {{ ($menuParent=='Users') ? 'active' : '' }} @endif">
                <a href="#">
                    <i class="fa fa-user"></i> <span>Users</span>
                    <i class="fa fa-angle-left pull-right"></i>
                </a>
                <ul class="treeview-menu">
                    <li @if(isset($menuChild)) {{ ($menuChild=='viewUsers') ? "class=active" : "" }} @endif>
                        <a href="/admin/users"><i class="fa fa-circle-o"></i> Users overview</a>
                    </li>
                    <li @if(isset($menuChild)) {{ ($menuChild=='addUser') ? "class=active" : "" }} @endif>
                        <a href="/admin/user/add"><i class="fa fa-circle-o"></i> Add User</a>
                    </li>
                </ul>
            </li>
1 like
seomike's avatar

Bootstrap Menus With Dynamic active <li> tags

SEO Friendly solution

Solved this using View Composers

  • No, Javascript needed
  • No, Extra static lists needed
  • No, Messy IF ELSE logic in your views
  • No, Messy controllers at all
  • No, 3rd party package needed

Routes

routes/web.php

This uses named routes to as a means to generate the <li> tags with <a> links for Bootstrap <ul> navs using View Composers.

// Routes
Route::group(['middleware' => 'auth','prefix' => 'foo'], function ($router) {

    // Side Menu
    // The view composer will strip foo.sidenav. off the route name and use dashboard to create the link text in the <a>
    Route::get('/dashboard', ['as' => 'foo.sidenav.dashboard', 'uses' => 'DashboardController@index']);
    // The view composer will strip foo.sidenav. off the route name and use settings to create the link text in the <a>
    Route::get('/settings', ['as' => 'foo.sidenav.settings', 'uses' => 'SettingsController@index']);

    // Top Menu
    Route::get('/profile', ['as' => 'foo.topnav.profile', 'uses' => 'ProfileController@index']);    

});

Config

config/app.php

Register the service provider

/*
         * Application Service Providers...
         */
        App\Providers\AppServiceProvider::class,
        // App\Providers\BroadcastServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        App\Providers\ComposerServiceProvider::class,  // << add this composer service provider
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,

Build the Service Provider

app/Http/Providers/ComposerServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;

class ComposerServiceProvider extends ServiceProvider
{
    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function boot()
    {
        // Using class based composers...
    // We use the wild card matching to make sure this composer
    // is used on views called  to routes prefixed with /foo (/foo/dashboard /foo/settings)
    // change 'foo.*', '*' if you want all views to have access
        View::composer('foo.*', 'App\Http\Composers\SideNavComposer'
        );

    }

}

Create the Composer

app/Http/Composer/SideNavComposer.php

Now create the actual composer ;)

<?php

namespace App\Http\Composers;

use Illuminate\Http\Request;
use Illuminate\Routing\Router;
use Illuminate\View\View;

class SideNavComposer
{
    /**
     * @var Router
     */
    protected $router;

    /**
     * @var Request
     */
    protected $request;

    /**
     * Route name prefix / for matching
     * This will cause the composer to only target named routes that begin with foo.sidenav
     * @var string
     */
    protected $prefix = 'foo.sidenav.';

    /**
     * Create a new SideNav composer.
     *
     * @param Illuminate\Routing\Router $router
     * @param Illuminate\Http\Request $request
     */
    public function __construct(Router $router, Request $request)
    {
        // Ooooh baby gimme those routes
        $this->router = $router;
    
    // ... And the current request too
        $this->request = $request;
    }

    /**
     * Bind data to the view.
     *
     * @param  View $view
     * @return void
     */
    public function compose(View $view)
    {
        // Format links
        $list = $this->createListItems();

    // WHERE THE MAGIC HAPPENS
        // return $sidenav array with any views that are called
        $view->with('sidenav', $list);
    }

    /**
     * Create <li> list items w/ <a> as per composer parameters
     *
     * @return array
     */
    protected function createListItems()
    {
        $list = [];
    
    // Loop through the routes
        foreach ($this->router->getRoutes() as $route) {

            if (strstr($route->getName(), $this->prefix)) {

                // Activate current link ? leave blank
                $active = ($route->uri() == $this->request->path()) ? ' class="active"' : '';
        // Create URI
                $uri = '/' . $route->uri();
        // Create link text 
                $text = $this->makeLinkText($route->getName());

                // Push list item
                $list[] = '<li' . $active . '><a href="' . $uri . '">' . $text . '</a>';
            }

        }

        return $list;

    }

    /**
     * Make link text for <a> tag
     *
     * @param $name
     * @return string
     */
    protected function makeLinkText($name)
    {
        return ucfirst(str_replace($this->prefix, '', $name));
    }
}

View Files

resources/views/layouts/app.blade.php

<!DOCTYPE html>
<html lang="en">
<head><link href="{{elixir('css/app.css')}}" rel="stylesheet"></head>
<body>
<div class="container-fluid">

    <div class="row">

        <!-- Left nav -->
        <div class="col-md-2">
            <div class="panel panel-default">
                
        <div class="panel-body">
            <ul class="nav nav-pills nav-stacked">
                
                <!-- SideNavComposer ready for use -->
                    @foreach($sidenav as $list)
                        {!! $list !!}
                    @endforeach 
            <!-- Holy Sh!t that's clean ;) -->

            </ul>
                </div>

            </div>

        </div>

        <!-- Content -->
        <div class="col-md-10">
            <div class="panel panel-default">
                <div class="panel-body">

                    @yield('content')

                </div>
            </div>

        </div>

    </div>

</div>

<!-- Scripts -->
<script src="/js/app.js"></script>
</body>
</html>

resources/views/dashboard.blade.php

@extends('layouts.app')

@section('content')
    Some Dashboard contentDashboard
@endsection

Controller

app/Http/Controllers/DashboardController.php

<?php

namespace App\Http\Controllers;

class DashboardController extends Controller
{
    /**
     * Show the application dashboard.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return view('dashboard');
    }
}

Want a new sidemenu link. Easy Just add a new route prefixed with foo.sidenav.

<?php
Route::group(['middleware' => 'auth','prefix' => 'foo'], function () {
    //...   
    Route::get('/bar', ['as' => 'foo.sidenav.bar', 'uses' => 'SomeController@index']);
    Route::get('/cancel', ['as' => 'foo.sidenav.cancel', 'uses' => 'SomeController@index']);
    Route::get('/billing', ['as' => 'foo.sidenav.billing', 'uses' => 'SomeController@index']);
});

Now make a Composer for top nav or bottom nav etc. Enjoy!

3 likes
Szyfr's avatar

ofcourse this will not work,

<li class="{{ Request::is('home') ? 'class="active"' : '' }}"><a href="{{URL::to('clients')}}">Home</a></li>

should be

<li class="{{ Request::is('home') ? 'active' : '' }}"><a href="{{URL::to('home')}}">Home</a></li>

see the difference?

3 likes
CODEheures's avatar

My solution with named routes (Test on Laravel 5.3):

1°) Get the current route name

<?php $routeName =  \Illuminate\Support\Facades\Route::getFacadeRoot()->current()->getName() ?>

2°) Test if the current route name is same as href route name

<a href="{{ route('home') }}" class="{{ $routeName == 'home' ? 'active' : '' }}">Home</a>
Devon's avatar

Like @seomike, I prefer using a view composer than anything else. However, I don't like hard-coding that logic into a view composer. Therefore, I opted to take a bit of a hybrid approach. What I did was:

  1. Create a ViewComposerServiceProvider as explained in the 5.3 docs on View Composers.
  2. Update the app\config.php to load the new service provider.
  3. Create an ActiveLinkComposer, as illustrated in the PHP snippet below.
  4. Configure my ViewComposerServiceProvider to load the ActiveLinkComposer
  5. Use the activeRoute and activePath methods in my views, as illustrated in the blade snippet below.

Active Link Composer

<?php

namespace App\Services\ViewComposers;

use Illuminate\View\View;
use Illuminate\Support\Str;
use Illuminate\Http\Request;

class ActiveLinkComposer
{
    /**
     * @var \Illuminate\Http\Request
     */
    private $request;

    /**
     * @var string
     */
    private $activeClass = 'active';

    /**
     * @var string
     */
    private $template = ' class="{classes}"';

    /**
     * Create a new profile composer.
     *
     * @param \Illuminate\Http\Request $request
     * @return void
     */
    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    /**
     * Bind data to the view.
     *
     * @param  View  $view
     * @return void
     */
    public function compose(View $view)
    {
        $view->with('link', $this);
    }

    /**
     * Determine if a link should be marked as active based on the provided route(s)
     * and return the class attribute. Optionally, you can override the template
     * to only return the class list or individual active state for the link.
     *
     * @param $routes string|array A single or list of routes to match against.
     * @param string $classes string A string of classes to be returned with the state.
     * @param null $activeClass string A string to override the $this->activeClass.
     * @param null $template string A string to override $this->template
     * @return string
     */
    public function activeRoute($routes, $classes = '', $activeClass = null, $template = null)
    {
        return $this->buildClassList(
            $routes, $this->request->route()->getName(), $classes, $activeClass, $template
        );
    }

    /**
     * Determine if a link should be marked as active based on the provided path(s)
     * and return the class attribute. Optionally, you can override the template
     * to only return the class list or individual active state for the link.
     *
     * @param $paths string|array A single or list of paths to match against.
     * @param string $classes string A string of classes to be returned with the state.
     * @param null $activeClass string A string to override the $this->activeClass.
     * @param null $template string A string to override $this->template
     * @return string
     */
    public function activePath($paths, $classes = '', $activeClass = null, $template = null)
    {
        return $this->buildClassList(
            $paths, $this->request->decodedPath(), $classes, $activeClass, $template
        );
    }

    /**
     * Determine if a link should be marked as active based on provided patterns(s)
     * and return the class attribute. Optionally, you can override the template
     * to only return the class list or individual active state for the link.
     *
     * @param $patterns string|array A single or list of patterns to match against.
     * @param $value string The string to match the patterns against.
     * @param string $classes string A string of classes to be returned with the state.
     * @param null $activeClass string A string to override the $this->activeClass.
     * @param null $template string A string to override $this->template
     * @return string
     */
    private function buildClassList($patterns, $value, $classes, $activeClass, $template)
    {
        if ($this->matches($patterns, $value)) {
            $classes = trim(implode(' ', [$classes, $activeClass ?: $this->activeClass]));
        }

        return str_replace('{classes}', $classes, $template ?: $this->template);
    }

    /**
     * Determine if any of the provided patterns match the given value.
     *
     * @param $patterns string|array A single or list of patterns to match against.
     * @param $value string The string to match the patterns against.
     * @return bool
     */
    private function matches($patterns, $value)
    {
        foreach ((array) $patterns as $pattern) {
            if (Str::is($pattern, $value)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Set the active class to be used on future calls.
     *
     * @param $activeClass
     * @return $this
     */
    public function class($activeClass)
    {
        $this->activeClass = $activeClass;

        return $this;
    }

    /**
     * Set the template to be used on future calls.
     *
     * @param $activeTemplate
     * @return $this
     */
    public function template($activeTemplate)
    {
        $this->template = $activeTemplate;

        return $this;
    }
}

Blade Template

(Do note that they should be used in {!! !!} tags to avoid being escaped when in HTML. All examples assume I'm on setup/requirements and it's named setup.requirements)

{{-- Single path wildcard, matches. Returns: class="active" --}}
{{ $link->activePath('setup/*') }}<br>

{{-- Single path, matches. Includes other classes. Returns: class="link-item active" --}}
{{ $link->activePath('setup/requirements', 'link-item') }}<br>

{{-- Multiple paths, matches. Overrides active class. Returns: class="link-item active-item" --}}
{{ $link->activePath(['setup/*', 'mismatch/path'], 'link-item', 'active-item') }}<br>

{{--Single route wildcard, matches. Overrides template. Returns: link-item active--}}
{{ $link->activeRoute('*.requirements', 'mismatch.route', 'link-item', null, '{classes}') }}<br>

{{-- Single route, matches. Sets new default active class and template. Returns: data-class="link-item activated" --}}
{{ $link->class('activated')->template(' data-class="{classes}"')->activeRoute('setup.*', 'link-item') }}<br>

{{-- Multiple routes, matches. Uses above template and class. Returns: data-class="link-item active-item" --}}
{{ $link->activeRoute(['setup.requirements', 'mismatch.route'], 'link-item', 'active-item') }}<br>

{{-- Multiple routes, matches. Uses above template and class. Returns: data-class="link-item active-item" --}}
{{ $link->activeRoute(['setup.requirements', 'mismatch.route'], 'link-item', 'active-item') }}<br>

{{-- Multiple routes, doesn't match. Returns: ng-class="link-item" --}}
{{ $link->activePath(['requirements', 'mismatch.route'], 'link-item', 'active-item', ' ng-class="{classes}"') }}<br>

So basically it's pretty short and sweet but yet is flexible for those edge cases where you just need a bit more control. You can also wrap your links in a separate template and @include('partials.link', ['var' => $val, …])them with variables passed as additional arguments to try and keep your templates a bit cleaner.

4 likes
Awks's avatar

Hello,

My turn, what i'm doing to achieve this :

My routing names convention

    admin.dashboard
    admin.portfolio.index
    admin.portfolio.create
    admin.portfolio.store
    admin.portfolio.show

        ...

My view

<ul class="nav nav-tabs">
    <li role="presentation" class="{{ strpos(Route::currentRouteName(), 'admin.dashboard') !== false ? 'active' : null }}">
        <a href="{{ route('admin.dashboard.index') }}"><i class="fa fa-pie-chart"></i> Dashboard</a>
    </li>
    <li role="presentation" class="{{ strpos(Route::currentRouteName(), 'admin.portfolio') !== false ? 'active' : null }}">
        <a href="{{ route('admin.portfolio.index') }}"><i class="fa fa-archive"></i> Portfolio</a>
    </li>

    ...

</ul>

It will set the active class for the parent route (admin.portfolio) and his childrens (admin.portfolio.*).

What do you think ?

Enjoy!

jjudge's avatar

@awks If you specifically check for equality to zero, then you can make sure the route starts with the relevant string:

{{ strpos(Route::currentRouteName(), 'admin.dashboard') === 0 ? 'active' : '' }

That will match admin.dashboard.bar but not foo.admin.dashboard.bar. That may or may not be what you want, but it's something you can do.

I would also return and empty string instead of null, then there is no type-casting needed, since {{ ... }} will be expecting a string to be returned, or will need to cast whatever is returned to a string. Just start with a string and get it over with.

mustard's avatar

There is a very simple way to sort this out in Laravel 5. In your layout/master file, add the following function:

<?php 
  function current_page($uri = "/") { 
    return strstr(request()->path(), $uri); 
  } 
?>

Then in your menu, just test against this logic and apply the "active" class:

 <li class="nav-item {{current_page('about') ? 'active' : '' }}">
       <a class="nav-link" href="/about">About</a>
 </li>

Simple!

jjudge's avatar

@mustard Yes, you can look at the URL path, but you must stay aware of what the implications of that are.

Paths are generally (and should always IMO) be defined in the routes.php map. Outside of that script, I don't believe views or controllers should be aware of what those paths are. Paths can easily change as an application develops and grows. The names of the paths however, can remain fixed since they define a business function.

But horses for courses - it's not wrong, just understand what its advantages and limitations are.

1 like
stevenbauman's avatar

For anyone viewing this in the future, laravel supports wildcards in the Route::is() method. There's no reason to use any complicated regular expressions or custom classes:

<a href="/accounts" class="{{ Route::is('accounts.*') ? 'active' : null }}">Accounts</a>

This link will have an active class when viewing any routes that start with accounts..

You can also use prefix wildcards, so you can check if the current route contains any name at all:

<a href="/accounts" class="{{ Route::is('*.accounts.*') ? 'active' : null }}">Accounts</a>

The above link will be active if the users current route contains .accounts..

1 like
luddinus's avatar

This is what I use (keep it simple)

app/helpers.php

function active_if($routeNames)
{
    $routeNames = (array) $routeNames;

    foreach ($routeNames as $routeName) {
        if (Route::is($routeName)) {
            return ' class="active"';
        }
    }

    return '';
}
    

some view

<li{!! active_if('login') !!}><a href="{{ route('login') }}">Login</a></li>
1 like
jjudge's avatar

@stevenbauman when did Route::is() appear in Laravel? I can't see it in the latest on github, but I may be looking in the wrong place.

Request::is() has been a thing for a long time, and takes wildcards, but works on URL paths, not route names.

rulatir's avatar

All these solutions are unsatisfactory. The real problem here is as follws:

GIVEN: a URI

DETERMINE WHETHER: if the given URI were requested, would the request hit the same route/controller/action triplet as the current request and would the action also receive the same parameter values?

A satisfactory solution would be one that solves this problem without ANY manual hints like assigning names to routes. If I have a route that parses the page slug with a wildcard, then naming the route is not enough. I don't just wan't to know that I have hit the page route, I also want to know if I hit the same specific page the given URI would hit. Route naming doesn't solve that.

Next

Please or to participate in this conversation.