Cms: [Feature Request] Add "title" argument to Twig svg() function

Created on 2 Mar 2019  ·  5Comments  ·  Source: craftcms/cms

The <title> tag of an <svg> can be used to provide alternative text for accessibility reasons. It would be nice if we could add/replace the <title> tag when inlining SVGs with the svg() function in Twig. Sometimes the same icon can mean different things depending on the context, or on a multilingual site you may want to translate it.

enhancement site development

Most helpful comment

Just added new |append and |prepend Twig filters for Craft 3.3, which append/prepend HTML elements to another element, including SVGs.

{{ svg('@webroot/icons/wave.svg')
    |append('<title>Waving Hand</title>')
    |append('<desc>A waving hand icon.</desc>') }}

If you think the SVG may already contain <title> / <desc> elements, then you can pass a second argument that determines how that should be handled to avoid duplicate elements:

  • 'keep' will leave the existing element alone and not add the new one
  • 'replace' will replace the existing element with the new one
{{ svg('@webroot/icons/wave.svg')
    |append('<title>Waving Hand</title>', 'keep')
    |append('<desc>A waving hand icon.</desc>', 'replace') }}

I’ve also added a new tag() Twig function, for rendering HTML tags using a declarative syntax:

{{ svg('@webroot/icons/wave.svg')
    |append(tag('title', {text: 'Waving Hand'}), 'keep')
    |append(tag('desc', {text: 'A waving hand icon.'}), 'replace') }}

You can combine these new filters with the new |attr filter as well:

{{ svg('@webroot/icons/wave.svg')
    |attr({role: 'img', 'aria-labelledby': 'title  desc'})
    |append(tag('title', {id: 'title', text: 'Waving Hand'}), 'replace')
    |append(tag('desc', {id: 'text', text: 'A waving hand icon.'}), 'replace') }}

Or even move all this into a custom macro:

{% macro accessibleSvg(svg, title, desc) %}
    {%- set ns = 'svg' ~ random() %}
    {{- svg(svg)
        |attr({role: 'img', 'aria-labelledby': "#{ns}-title  #{ns}-desc"})
        |append(tag('title', {id: "#{ns}-title", text: title}), 'replace')
        |append(tag('desc', {id: "#{ns}-desc", text: desc}), 'replace') }}
{%- endmacro %}

{{ _self.accessibleSvg(
    '@webroot/icons/wave.svg',
    'Waving Hand',
    'A waving hand icon.'
) }}

All 5 comments

I could envision a more general tags param being useful. It could accept an array of tag names as keys, and markup as values — to allow adding/replacing title _or_ desc.

Closing this in favor of #4660

Sorry, just realized this is referring to a <title> HTML element, not the title attribute. Reopening.

Just added new |append and |prepend Twig filters for Craft 3.3, which append/prepend HTML elements to another element, including SVGs.

{{ svg('@webroot/icons/wave.svg')
    |append('<title>Waving Hand</title>')
    |append('<desc>A waving hand icon.</desc>') }}

If you think the SVG may already contain <title> / <desc> elements, then you can pass a second argument that determines how that should be handled to avoid duplicate elements:

  • 'keep' will leave the existing element alone and not add the new one
  • 'replace' will replace the existing element with the new one
{{ svg('@webroot/icons/wave.svg')
    |append('<title>Waving Hand</title>', 'keep')
    |append('<desc>A waving hand icon.</desc>', 'replace') }}

I’ve also added a new tag() Twig function, for rendering HTML tags using a declarative syntax:

{{ svg('@webroot/icons/wave.svg')
    |append(tag('title', {text: 'Waving Hand'}), 'keep')
    |append(tag('desc', {text: 'A waving hand icon.'}), 'replace') }}

You can combine these new filters with the new |attr filter as well:

{{ svg('@webroot/icons/wave.svg')
    |attr({role: 'img', 'aria-labelledby': 'title  desc'})
    |append(tag('title', {id: 'title', text: 'Waving Hand'}), 'replace')
    |append(tag('desc', {id: 'text', text: 'A waving hand icon.'}), 'replace') }}

Or even move all this into a custom macro:

{% macro accessibleSvg(svg, title, desc) %}
    {%- set ns = 'svg' ~ random() %}
    {{- svg(svg)
        |attr({role: 'img', 'aria-labelledby': "#{ns}-title  #{ns}-desc"})
        |append(tag('title', {id: "#{ns}-title", text: title}), 'replace')
        |append(tag('desc', {id: "#{ns}-desc", text: desc}), 'replace') }}
{%- endmacro %}

{{ _self.accessibleSvg(
    '@webroot/icons/wave.svg',
    'Waving Hand',
    'A waving hand icon.'
) }}

Very cool! 👍

Was this page helpful?
0 / 5 - 0 ratings