Monday, March 8, 2010

Django current 'active' page highlighting for navigation

It is pretty common to want to highlight the current page in your navigation bar. Unfortunately it is surprisingly hard to do with django. After reading a few blogs I decided on the following, which involves creating a custom template tag and enabling the request context processor. First create a custom template tag (don't forget the __init__.py in your templatetags directory):

#!/usr/bin/env python
#project/site/templatetags/active.py

from django import template
register = template.Library()

@register.simple_tag
def active(request, pattern):
import re
if re.search(pattern, request.path):
return 'current_page_item'
return ''

Add names to your views in urls.py so you can reference the regex in the template. The prototype is '(regular expression, Python callback function [, optional dictionary [, optional name]])':

(r'^$', 'home view', {}, 'home')

Then in your template:

{% load active %}
{% url home as home %}

<li class="{% active request home %}">Home</li>


In settings.py define the 'request' context processor (you also have to define the other defaults so you don't lose them):

TEMPLATE_CONTEXT_PROCESSORS = ('django.core.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.request')

Now you just need a line in your CSS that does somehthing different for the 'current_page_item' class.

3 comments:

Dhiraj Thakur said...

You can also do this when you are rendering the template...

i added {% block activepage %}{% endblock %} in my base template and in a page which extended from the basic template i added {% block activepage %} class="active" {% endblock %} where active class does the highlight in CSS.

Hope this also helps somebody... :)

G said...

@Dhiraj: not sure I understand your comment.

This post is about applying different style to an item in a navigation bar. With your example how do you know which item should have class="active"?

iannakin said...

@G
I actually like Dhiraj Thakur's method, it's not best practices, but it's really quick to put up.

Let's say you have such a template hierarchy :

templates/base.html
templates/index.html (extends base.html)
templates/about.html (extends base.html)

You could have something like :

#templates/base.html
...
<ul>
<li class="{% block link_home_class %}{% endblock %}"><a href="/">Home</a>
<li class="{% block link_about_class %}{% endblock %}"><a href="/about">About</a>
</ul>
...


Then, in your derivative templates :

#templates/index.html
{% extends "base.html" %}
{% block link_home_class %}active{% endblock %}
...


#templates/about.html
{% extends "base.html" %}
{% block link_about_class %}active{% endblock %}
...


Now you just have to style your active li with something like :

ul li.active {
/* some css code */
}

or, to style the anchor directly
:
ul li.active a {
/* some css code */
}