How to use svg icons in Django templates?

October 4, 2016

I am accustomed to use icon fonts in our projects at Dreamsolution, which are created with Fontcustom. It is a nice tool to generate the font icon from our own svg icons. Using the icon font in the last 3 years I always bump into some styling issues. The icon font has anti-alias and doesn't get as sharp as vector images. The most annoying thing is positioning the icon next another element or text. You have to take into account the vertical alignment, line-height, letter-spacing etc, after all, it is a font. To position it correctly in the latest browsers, you have to do a lot of tweaking.

I was curious if you can use svg icons in an maintainable way. After reading the article on CSS-tricks about svg symbols and Sara Soueidans' article about svg sprites, I created a little demo page using this technique and discussed it with my colleagues to give this technique a chance in one of our projects. Because of the great advantages of svg, the decision was easily made.

The project we started to use svg symbols is build with Django Framework. The svg icons are created separately and placed in a folder called svg-icons. This folder is purely for version control.

In the templates directory I created the include template file include_icon_sprite.html. It is a html file, because at the time of writing we still need to support IE and IE does not support xlink with external reference to an svg file. I include this file in the base template at the bottom of the page. Using "include" in the file name we know it is a template snippet. In this file I have one svg file which contains all the symbols. The symbol contains the svg code copied from each svg icon from the svg-icons directory.

In the code snippet you'll notice the class svg-sprite. If you do not hide the svg, all the icons will be displayed. In your Sass or CSS file you set .svg-sprite { display: none; }.


<svg xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink" class="svg-sprite"
        viewBox="0 0 512 512" >
    <symbol id="filter">
        <path d="M0 26h512v51.206L307.21 333.213v153.6l-102.404-51.208V333.213L0 77.206V26z" />
    </symbol>
    <symbol id="home">
        <path d="M512 296l-96-96V56h-64v80l-96-96L0 296v16h64v160h160v-96h64v96h160V312h64v-16z" />
    </symbol>
</svg>

To use a symbol you could place the following code in the template every time you need an icon:


<ul>
    <li>
        <a href="{% url "home" %}" class="menu-item">
            <svg viewBox="0 0 512 512" class="icon-home">
                <use xlink:href="#home"></use>
            </svg>
            Home
        </a>
    </li>
    <li>
        <a href="{% url "filter" %}" class="menu-item">
            <svg viewBox="0 0 512 512" class="icon-home">
                <use xlink:href="#filter"></use>
            </svg>
            Filter
        </a>
    </li>
</ul>

Instead of typing this every time I need an icon, I created a template tag called icon.py. In the djangoproject documentation you can find more information about custom template tags.


from django import template
from django.utils.safestring import mark_safe
from django.utils.html import format_html

register = template.Library()


@register.simple_tag(name='svg_icon')
def svg_icon(icon_name, extra_class=''):
    svg_tag = format_html('<svg viewBox="0 0 512 512" width="10" height="10"'
        'class="icon-{name} {extra}">'
        '<use xlink:href="#{name}"></use>'
        '</svg>', name=icon_name, extra=extra_class)

    return mark_safe(svg_tag)

This custom tag has 2 variables, the icon_name and extra_class. If you need a specific styling for the icon you can set an extra class. To use the custom template tag in your template you have to load the template tag in your Django template and you are ready to go:


{% load icon %}
<ul>
    <li>
        <a href="{% url "home" %}" class="menu-item">
            {% svg_icon "home" %} Home
        </a>
    </li>
    <li>
        <a href="{% url "filter" %}" class="menu-item">
            {% svg_icon "filter" %} Filter
        </a>
    </li>
</ul>

The only thing left to do is to give the icon a width/height and a color. In this example all the icons get the same styling.


[class^="icon-"] {
    width: 2rem;
    height: auto;
    fill: #222;
}

This is a short tutorial how to use svg icons in Django templates. I hope this article is useful to you.