Accessibility
Swarm Icons handles the most common accessibility patterns for you. Most of the time, you don’t need to think about it. The defaults do the right thing.
The two kinds of icons
Section titled “The two kinds of icons”Every icon on a page is either decorative or meaningful:
- Decorative icons sit next to text that already explains what’s going on. A trash can icon next to the word “Delete”: the icon is decoration, the text carries the meaning.
- Meaningful icons stand alone as the only way to understand an action. A trash can icon with no text: screen readers need to know what it does.
Swarm Icons detects which case you’re in and adds the right ARIA attributes automatically.
Decorative icons (the default)
Section titled “Decorative icons (the default)”If you don’t pass aria-label or aria-labelledby, the icon is treated as decorative and hidden from screen readers:
echo swarm_icon('tabler:home');// → <svg aria-hidden="true" ...>...</svg>This is the right behavior for the majority of icons (the ones that sit next to visible text):
echo swarm_icon('tabler:home') . ' Home';echo '<button>' . swarm_icon('tabler:trash') . ' Delete</button>';echo '<a href="/">' . swarm_icon('tabler:home') . ' Dashboard</a>';In all of these, the text does the communicating. The icon is visual reinforcement.
Meaningful icons
Section titled “Meaningful icons”When an icon is the only indicator of what something does, give it an aria-label. Swarm Icons will add role="img" automatically:
echo swarm_icon('tabler:home', ['aria-label' => 'Home']);// → <svg role="img" aria-label="Home" ...>...</svg>This matters most for icon-only controls:
// Icon-only buttonecho '<button>' . swarm_icon('tabler:trash', ['aria-label' => 'Delete item']) . '</button>';
// Icon-only linkecho '<a href="/settings">' . swarm_icon('tabler:settings', ['aria-label' => 'Settings']) . '</a>';Without aria-label, a screen reader user wouldn’t know what these controls do.
You can also use aria-labelledby to reference another element on the page:
echo '<h2 id="section-title">Dashboard</h2>';echo swarm_icon('tabler:layout-dashboard', ['aria-labelledby' => 'section-title']);Overriding the defaults
Section titled “Overriding the defaults”If you set aria-hidden or role yourself, Swarm Icons won’t touch them:
echo swarm_icon('tabler:home', ['role' => 'presentation']);echo swarm_icon('tabler:home', ['aria-hidden' => 'true', 'aria-label' => 'Home']);The automatic behavior only kicks in when those attributes aren’t already present.
Practical guidelines
Section titled “Practical guidelines”Let most icons be decorative. If there’s text next to it, the icon doesn’t need a label. This is the default. You don’t need to do anything.
Label icon-only controls. Any button, link, or input that has no visible text needs aria-label:
echo '<button>' . swarm_icon('tabler:x', ['aria-label' => 'Close']) . '</button>';Don’t double up. If the text already says “Delete”, don’t also label the icon “Delete”: a screen reader would announce it twice:
// Good: icon is decorative, text carries the meaningecho swarm_icon('tabler:trash') . ' Delete';
// Avoid: screen reader says "Delete Delete"echo swarm_icon('tabler:trash', ['aria-label' => 'Delete']) . ' Delete';In Twig
Section titled “In Twig”The same rules apply: the rendering pipeline is identical:
{# Decorative #}{{ icon('tabler:home') }} Home
{# Meaningful #}{{ icon('tabler:home', {'aria-label': 'Go to homepage'}) }}See also
Section titled “See also”- Fluent API: setting
aria-labeland other attributes via theattr()method - Twig Integration: using icons in Twig templates