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.
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! 👍
Most helpful comment
Just added new
|appendand|prependTwig filters for Craft 3.3, which append/prepend HTML elements to another element, including SVGs.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 oneI’ve also added a new
tag()Twig function, for rendering HTML tags using a declarative syntax:You can combine these new filters with the new
|attrfilter as well:Or even move all this into a custom macro: