SVG accessibility: titles, roles and inline icons

Give an informative inline SVG role="img" and a name, taken from aria-label or from a title element that aria-labelledby points to. Hide a decorative SVG with aria-hidden="true". For an icon inside a button or link, put the name on the button or link and hide the drawing.

Published . Last reviewed .

An inline SVG, meaning SVG markup written straight into the HTML page, has no alt attribute, so the only text alternative it has is the one you add. W3C's Understanding page for WCAG 1.1.1 says non-text content needs a text alternative that serves the equivalent purpose, and that a control needs a name that describes its purpose (our WCAG 1.1.1 explainer covers the criterion). The name is the text a screen reader announces for an element. SVG offers several ways to supply it, and they do not all behave the same.

Two W3C documents set the background. The ARIA in HTML specification lets an svg element take any role, though it advises against setting graphics-document, the role SVG maps to by default. The img role in WAI-ARIA 1.2 fits a drawing: it is "a container for a collection of elements that form an image", and authors must name it with aria-label or aria-labelledby. The SVG naming rules live in the SVG Accessibility API Mappings (SVG-AAM), which is still a W3C Working Draft and calls itself an early draft. Treat it as background, not as a promise about what any browser or screen reader does.

Which markup fits which SVG

How the SVG reaches the page decides what it needs, and the choice between meaning and decoration is the one from our alt text guide. The table gives the short version, and the sections below explain each row.

Six ways an SVG appears on a page and the markup that gives it a text alternative or hides it
The SVG is...If it carries meaningIf it is decoration
Inline, on its ownrole="img" plus aria-label, or aria-labelledby pointing at a titlearia-hidden="true"
The only content of a button or linkName the button or link, for example with aria-labelNot applicable: the control needs a name
Beside visible text in a button or linkUsually nothing extra: the visible text is the namearia-hidden="true" on the SVG
A file loaded by an img elementalt text that gives its meaning or functionalt=""
A CSS backgroundNo text alternative is possible, so do not use it for meaningFine, with no markup
A sprite referenced with useName it on the outer svg or the control around itaria-hidden="true" on the outer svg

Informative inline SVG: role, name and description

An SVG is informative when taking it away would lose something: a status icon, a logo that is the only thing naming a site, a small diagram. Two patterns cover most pages. The first puts the label on the SVG itself:

<svg role="img" aria-label="In stock" viewBox="0 0 24 24">
  <path d="..." />
</svg>

The second keeps the words inside the SVG, in a title element that the SVG points to:

<svg role="img" aria-labelledby="stock-title" viewBox="0 0 24 24">
  <title id="stock-title">In stock</title>
  <path d="..." />
</svg>

MDN describes the SVG title element as providing "an accessible, short-text description" of a container or graphics element. It says that, for backward compatibility with SVG 1.1, a title should be the first child of its parent, and that its text is not rendered as part of the graphic but browsers usually display it as a tooltip. Choose the second pattern when you want that tooltip and the first when you do not. MDN adds that if visible text can describe the element, you should reference that text with aria-labelledby instead, which suits a chart that already has a visible heading.

Why add an explicit reference when a title alone should work? The SVG-AAM draft orders its name sources as aria-labelledby, then aria-label, then a direct child title, so a bare title is expected to work. WAI-ARIA, though, asks for aria-label or aria-labelledby on the img role, and an explicit pattern does not depend on a draft. Carie Fisher's 2021 comparison of SVG patterns on Smashing Magazine ran them through various screen readers. It rated role="img" with a title, and the same pattern with aria-labelledby pointing at the title, as "Best In Show". It rated a title plus desc without aria-labelledby as "Use Caution". She adds that each screen reader has browsers it fully supports and results can be less accurate in others, so test the pairings your visitors use.

Write what the SVG means or does, not what it looks like. W3C's functional images tutorial contrasts "print this page" with "printer", and "search" with "magnifying lens". Leave out words such as "icon" and "image": the role already tells the listener what kind of thing it is. Our alt text length guide and alt text examples apply to SVG names too.

Two limits follow from the img role. Under WAI-ARIA 1.2 its children are presentational, so the shapes and text inside an SVG marked role="img" are not meant to be exposed as separate items. Whatever the user needs must be in the name, in a description or in the page beside the SVG. For a longer description, MDN says a desc element gives "an accessible, long-text description", and that aria-describedby takes precedence over it if both are present. For a chart, put the figures in a table or paragraph near it, as our chart alt text guide shows.

Decorative SVG: hide it

A decorative SVG adds no information: a flourish, a divider, or an icon that repeats the text beside it. W3C's alt decision tree sends such images to an empty alt, and Understanding 1.1.1 says decoration should be implemented so assistive technology can ignore it. An inline SVG has no alt to leave empty, so hide it:

<svg aria-hidden="true" viewBox="0 0 24 24"><path d="..." /></svg>

The SVG-AAM draft says an element that has aria-hidden="true", or sits inside one that does, should not be exposed, and that an author-set none or presentation role keeps an element out too, unless it can take focus. The same draft says shapes, groups and similar child elements inside an SVG should normally be left out of the tree anyway, but it does not list the svg element itself, so state the choice rather than leave it to each browser.

Two cautions. First, hide only what is truly redundant: if the SVG is the only thing that names a control or carries a fact, hiding it removes that fact. Second, put aria-hidden on the drawing inside a control, never on a link or button itself. GotAlt's rule checks flag aria-hidden on a focusable element under WCAG 4.1.2 (see what we check). Our decorative images guide covers the empty-alt side, and background and CSS images covers the cases where no markup is needed at all.

Inline icons in buttons and links

Icons are the most common inline SVG, and the name should live on the control, not the drawing.

Three icon cases, where the name comes from and what goes on the SVG
CaseThe name comes fromOn the SVG
Icon beside visible text, such as "Add to cart"The visible textaria-hidden="true"
Icon is the only content, such as a search buttonaria-label on the button or link, or visually hidden text inside itaria-hidden="true"
Icon adds meaning inside link text, such as "opens in a new window"The icon's own name, read as part of the linkrole="img" and aria-label

For an icon-only button, the markup is short:

<button type="button" aria-label="Search">
  <svg aria-hidden="true" viewBox="0 0 24 24"><path d="..." /></svg>
</button>

W3C's technique ARIA6 describes aria-label as providing the text label for an object such as a button. Without any name, a screen reader announces only "button" or "link". GotAlt's free scan flags links and buttons with no accessible name for this reason, and our WCAG 2.4.4 explainer covers links.

When a button has visible text, do not give it an aria-label that says something else. Success criterion 2.5.3 Label in Name asks that the name contain the text presented visually, because people using speech input say the visible words. The icon alt text guide and logo guide cover more cases.

If the icon is clickable, wrap it in a real button or a. The ARIA Authoring Practices Read Me First page states that "ARIA roles do not cause browsers to provide keyboard behaviors or styling", so an svg given role="button" still needs focus and key handling that you write. A native button needs none. Test it with the keyboard accessibility test.

SVG files, CSS backgrounds and sprites

An SVG loaded by an img element

When you write <img src="logo.svg" alt="...">, the browser treats the file as an image, and the usual alt rules apply: describe the meaning or function, or use alt="" for decoration. MDN's page on SVG as an image adds that some browsers restrict an SVG used as an image: JavaScript is disabled and external resources cannot be loaded, so a script inside such a file may not run. If the SVG must be interactive, inline it.

An SVG used as a CSS background

A CSS background has no text alternative. Understanding 1.1.1 lists failure F3 for conveying information only through CSS background images, so use this route for decoration alone.

A sprite built with symbol and use

MDN says a symbol element is not meant to be rendered and that only its instances, made with use, are. We therefore put the role and name, or aria-hidden, on the svg that holds the use element, or on the control around it:

<svg aria-hidden="true" viewBox="0 0 24 24"><use href="#icon-cart" /></svg>

Contrast, color and text inside an SVG

Understanding 1.4.11 counts a stand-alone icon with no text, such as a print icon, as a graphical object that needs 3:1 contrast against adjacent colors when it is needed to understand the content. It adds that text within a graphic must meet the contrast rules for text, as our 1.4.11 explainer and color contrast guide describe. Understanding 1.4.1 adds that color must not be the only visual means of conveying information, so do not mark status with color alone.

If words are part of an SVG, put the same words in its name. Where the technology can produce the look with real text, Understanding 1.4.5 asks for text rather than an image of text. In our reading, an SVG text element is text and letters converted to outlines are shapes. See images of text for when that matters.

Check it yourself

Start with the browser. In Chrome, the Accessibility tab in the Elements panel shows the accessibility tree, the subset of the DOM that matters to screen readers, along with computed properties for the selected element. Confirm that a meaningful SVG appears with a name and a decorative one does not. Then listen with a screen reader, because the tree only models what one will say.

  • Accessibility bookmarklet. Checks the live page as your browser has rendered it, so it reaches SVG that scripts inserted. It flags role="img" with no name, links with no accessible name and buttons with no accessible name.
  • Link text checker. Lists every link with the name a screen reader announces, so an icon-only link with no name shows up. It counts the link's own text, aria-label and aria-labelledby, and the alt text of an image inside, but not an aria-label on an svg inside the link, so name the link itself. Paste the page's HTML to include links that scripts add.
  • Alt text checker. Judges whether an image's alt text is true of the image. It compares JPEG, PNG, WebP and GIF files, so it does not open SVG files: read an SVG's alt text against the drawing yourself.
  • Contrast checker. Measures a color pair against the 3:1 and 4.5:1 thresholds, so it covers an icon and its background.

The free scan reads the HTML your server sends and runs rule checks that include links and buttons with no accessible name. Scan my site for free to see where icon-only controls lack a name. No automated check can tell you that a name is right for the drawing, so the listening test stays.

Keep it checked

SVG names break quietly: a new icon set ships, or a button is added without a label. GotAlt checks the pages you monitor every week, compares the alt text of described images with the images themselves (up to six images per page), runs its rule checks, opens monitored pages in a browser for contrast and other render-dependent checks (see what we check), and reports what changed. Plans start from $69 a month. Audit my whole site from $69/mo.

SVG accessibility questions

Does an SVG need alt text?

An SVG loaded with an img element takes alt text like any image. An inline svg has no alt attribute, so give a meaningful one role="img" and a name from aria-label, or from a title that aria-labelledby points to. Hide a decorative one with aria-hidden="true". WCAG 1.1.1 covers SVG as non-text content.

Should I use title or aria-label on an SVG?

Either can supply the name. WAI-ARIA asks for aria-label or aria-labelledby on an element with the img role, so pair role="img" with one of them. Use aria-label for a plain name. Use aria-labelledby pointing at a title when you also want the tooltip that, according to MDN, browsers usually show for a title.

How do I make an SVG icon in a button accessible?

Put the name on the button and hide the icon. For an icon-only button, add aria-label describing the action, such as Search, and aria-hidden="true" on the svg. If the button has visible text, hide the icon and let the text name the button, without an aria-label that differs from that text.

How do I hide a decorative SVG from screen readers?

Add aria-hidden="true" to the svg. The SVG-AAM draft says an element with that value, or inside one, should not be exposed. Put it on the drawing, never on a link or button, and only on SVG that adds nothing: hiding the one thing that names a control leaves it without a name.

Is the SVG title tooltip enough for accessibility?

No. The tooltip is a side effect: MDN notes that title text is not rendered as part of the graphic and that browsers usually show it as a tooltip. A title that aria-labelledby points to can name the SVG for screen readers, but a tooltip does not put the meaning on the page. If people need the words to understand an icon, show them as visible text.

Can a screen reader read text inside an SVG?

It depends on the markup. Under WAI-ARIA 1.2 the children of an element with the img role are presentational, so text inside an SVG marked role="img" is not meant to be exposed separately. Without that role, results vary by screen reader and browser. Put what the user needs in the name or description, or in the page beside the SVG, and test with the screen readers your visitors use.

Find icon controls with no name

The free scan runs 16 rule-based checks on up to 3 pages of your site, including links and buttons with no accessible name. It reads the HTML your server sends, so use the checks above for the rest. No signup.

Scan my site for free