Highlight current menu item in sidebar

I think your use of # for the href in your sample code is clouding the issue. I'm assuming your real-world scenario is actual real links and automatically highlighting them based on the active URL. If that's correct, then just do:

{% url something as url %}
<li{% if request.path == url %} class="active"{% endif %}><a href="{{ url }}">Link1</a></li>

Where, "something" is the name of a urlpattern or dotted-path to a view, etc. This assumes you're reversing the URL, obviously, so if you're using a static URL, you'd just hardcode it:

<li{% if request.path == "/my/full/url/path/" %} class="active"{% endif %}><a href="/my/full/url/path/">Link1</a></li>

If you've organized your project into a base.html template that is extended by other templates, e.g. appname/pagename.html, you can use a template-centric approach to highlighting the active navigation element.

This approach gives you some decoupling advantages, which I've noted in detail at the end of this answer.

I've found this approach to be very useful for handling broad navigation items that remain the same across most or all of a site. It is probably not an appropriate solution for more detailed navigation elements, such as rendering a dynamic list of items gleaned from your data store.

In your base.html template, add a block to each navigation element, giving unique names to the blocks:

<ul class="nav">
  <li class="{% block navbar_class-home %}{% endblock %}">
    <a href="#">Home</a>
  </li>
  <li class="{% block navbar_class-about %}{% endblock %}">
    <a href="#">About</a>
  </li>
  <li class="{% block navbar_class-pricing %}{% endblock %}">
    <a href="#">Pricing</a>
  </li>
</ul>

In your appname/pagename.html template, if you want one of the nav elements to appear active, override the appropriate block using active as the content. For example, to highlight the "About" item:

{% block navbar_class-about %} active {% endblock %}

When you use a view that renders that template, it'll render like this:

<ul class="nav">
  <li class="">
    <a href="#">Home</a>
  </li>
  <li class=" active ">
    <a href="#">About</a>
  </li>
  <li class="">
    <a href="#">Pricing</a>
  </li>
</ul>

This provides an initial rendering that doesn't rely on JavaScript. (You can modify the nav bar classes in place using JavaScript if you're doing a single-page app.)

For many (but not all) cases, this can be a better separation presentation from view logic:

  • You can modify views to attach site-navigation data to the template context, but doing so strongly couples the presentation to the view layer, and makes it more difficult to create reusable apps or to integrate third-party apps.

    The view is already selecting a named template, which means that you are already passing some navigation-related information to the template layer. That may be all you need.

  • You can use a template context processor to get some information about the view, but this just moves the strong coupling to another layer of the system, rather than staying within the template layer.


Better solution, with less code. Woks well with Bootstrap. Just change the "addClass" query to select your menu items.

On Javascript, create this function:

var highlight_menu = function(path) {
    /* Highlight current link */    
    $('.nav li').removeClass('active');
    $('.nav li:has(a[href="' + path + '"])').addClass('active')
};

On the base.html, call the JS function with the current path:

<script>
    highlight_menu('{{request.path}}');
</script>