Skip to content

{% icon %}

Concept

icon combines <svg> (via named *.html) with a <span> (before or after) it and an optional parent tag around it.

Invocation via Django Template Language
1
2
3
4
5
6
{% load fragments %}
<html>
  {# assumes heroicons as default unless modified #}
  {% icon name='x_mark_mini' aria_hidden="true" pre_text="Close menu" pre_class="sr-only"  %}
  {# re: 'x_mark_mini' (1), re: attributes (2) #}
</html>
  1. name='x_mark_mini' refers to a heroicon (default) svg copy/pasted into a file named 'heroicon_x.html'
  2. The aria_hidden attribute is converted to aria-hidden, pre_text and pre_class means add a <span class='sr-only'>Close menu<span> before (pre)_ the svg icon.
Output HTML after the Template is populated with the Context.
<html>
  <span class="sr-only">Close menu</span>
  <svg
    aria-hidden="true" class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="1.5" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
    <path d="M6 18L18 6M6 6l12 12" stroke-linecap="round" stroke-linejoin="round">
    </path>
  </svg>
</html>

Setup

In order to work, must configure settings.py (or its equivalent) to define a path and then add properly named .html files containing copy/pasted raw <svg> from sources.

src/config/_settings.py
FRAGMENTS = {
  "icons_prefix": "heroicons", # prefix
  "icons_path": BASE_DIR / "templates" / "svg" # folder must exist, must use Path
}

SVG Placement

  1. Copy <svg> markup from a source such as heroicons, bootstrap, etc.;

    The svg markup in the file will look like:

    x_mark_mini
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5">
      <path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
    </svg>
    
  2. The name of the file to be created is relevant. Note source, we'll call this the prefix (see FRAGMENTS['icons_prefix']);

  3. Create .html file found in FRAGMENTS['icons_path'] in the proper folder and paste the <svg> markup to that file. See placement:

    Prefix of source, name of svg
    1
    2
    3
    4
    5
    6
    7
    8
    ...
    ├── config/
    ├── static/
    ├── templates/
        ├── svg/
            ├── bootstrap_github.html # (1)
            ├── heroicons_x_mark_mini.html # insert svg markup here (2)
            ...
    
    1. Dissected (prefix used) bootstrap; (icon name) github. Use as: {% icon name='github' prefix="bootstrap" %}

    2. Dissected:

      1. prefix used: heroicons
      2. icon name: x_mark_mini

      Use as:

      1. {% icon name='x_mark_mini' prefix="heroicons" %}; or
      2. {% icon name='x_mark_mini' %} (since heroicons is the default).
    /src/templates/svg/heroicons_x_mark_mini.html
    <!-- note the created file's name -->
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5">
      <path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
    </svg>
    
  4. Filename follows convention prefix + _ + name (of the <svg> from the source).html.

  5. The user is responsible for renaming the file properly to match the prefix and name. Note the name must replace dashes - with underscores _.

Basis

Make an <svg> fragment, using a file found within the name + prefix + folder path, and add the appropriate css classes and attributes, optionally including parent/sibling tags when parameters dictate.

Parameters:

Name Type Description Default
name str

The prefixless (prefix_) name of the html file containing an <svg> icon, presumes to be formatted and included in the proper folder previously.

required
css str

Previously defined CSS to add to the <svg> icon. Defaults to None.

None
prefix str

Source of the svg file; needs to be declared in settings.py.

settings.FRAGMENTS.get('icons_prefix')
folder str

Where to find the template; needs to be declared in settings.py.

settings.FRAGMENTS.get('icons_path')
**kwargs dict

The following kwargs: pre_, post_, and parent_ args are respected by start_html_tag_helpers

{}

Returns:

Name Type Description
SafeText SafeText

Small HTML fragment visually representing an svg icon but which may contain related tags.

Source code in django_fragments/templatetags/fragments.py
Python
@register.simple_tag
def icon(
    name: str,
    prefix: str = settings.FRAGMENTS.get("icons_prefix"),
    folder: Path = settings.FRAGMENTS.get("icons_path"),
    css: str | None = None,
    **kwargs,
) -> SafeText:
    """Make an `<svg>` fragment, using a file found within the `name` + `prefix` + `folder` path, and add the appropriate
    css classes and attributes, optionally including parent/sibling tags when parameters dictate.

    Args:
        name (str): The prefixless (prefix_) name of the `html` file containing an `<svg>` icon, presumes to be formatted and included in the proper folder previously.
        css (str, optional): Previously defined CSS to add to the `<svg>` icon. Defaults to None.
        prefix (str, optional): Source of the svg file; needs to be declared in `settings.py`.
        folder (str, optional): Where to find the template; needs to be declared in `settings.py`.
        **kwargs (dict): The following kwargs: `pre_`, `post_`, and `parent_` args are respected by `start_html_tag_helpers`

    Returns:
        SafeText: Small HTML fragment visually representing an svg icon but which may contain related tags.
    """  # noqa: E501
    path = folder / f"{prefix}_{name}.html"
    html = render_to_string(str(path))
    svg_with_kwargs = wrap_svg(html_markup=html, css=css, **kwargs)
    return mark_safe(str(svg_with_kwargs).strip())