Meaningful images
When an SVG conveys information — a logo, an icon that stands alone, a chart — it must have an accessible name so screen readers can announce what it shows. Without one, a screen reader either skips the element entirely or reads out the raw SVG markup character by character, neither of which helps the user.
There are two solid patterns:
Pattern A: <title> as the first child
The <title> element placed as the first child of the <svg> gives the graphic a name that browsers also surface as a tooltip on hover. Pair role="img" with it so the browser exposes the SVG to the accessibility tree as a single image object — otherwise some screen readers walk into the SVG and read its internal structure instead.
An optional <desc> element immediately after <title> adds a longer description (think: image caption) for users who want more context. The ordering rule is strict: <title> must come first; <desc> second.
A screen reader encountering this announces something like: "Acme Co. logo: bold 'A' in burnt orange, image". The user can also press a key to hear the longer <desc> text. The tooltip appears visually on hover because browsers map <title> to the native tooltip mechanism — a useful bonus for sighted users too.
Pattern B: aria-label directly on the element
When you cannot or do not want to embed a <title> element (for example, the SVG is generated by a third-party library), aria-label on the <svg> tag is a clean alternative. Combine it with role="img" in exactly the same way. There is no tooltip effect with this approach, but the accessible name is fully equivalent.
Decorative SVG
Not every SVG carries meaning. A background flourish, a divider swirl, or a purely ornamental border adds visual interest but would only clutter the screen reader experience if announced. The rule is straightforward: if removing the SVG would not change the user's understanding of the page, it is decorative.
Hiding inline SVG with aria-hidden
Add aria-hidden="true" to remove the element from the accessibility tree entirely. Add focusable="false" as well — this is an old Internet Explorer quirk where SVG elements inside an <a> or with tabindex could still receive keyboard focus even when hidden from AT; the attribute prevents that on legacy browsers.
Screen readers skip this element completely. Tab focus never lands on it. Visually it is still rendered normally for sighted users.
Decorative <img> with SVG source
When you use an SVG as the src of an <img> element for decoration, supply an empty alt attribute (alt=""). This signals to assistive technology that the image is decorative — the browser then skips it in reading order. Omitting alt entirely is different: some screen readers will then announce the filename, which is rarely helpful.
Complex graphics — long descriptions
A simple label is sufficient for an icon. A bar chart, however, may encode data that a sighted user reads by examining the bars. For complex graphics, you need both a short name (what it is) and a longer description (what it shows). The combination of <title>, <desc>, and the ARIA pointer attributes aria-labelledby / aria-describedby makes this robust.
The pattern: give <title> and <desc> each an id, then point the SVG's aria-labelledby at the title's id and aria-describedby at the desc's id. Screen readers then surface both in a predictable order regardless of which ARIA implementation version the browser uses.
A screen reader announces this as: "Quarterly sales — Q1 to Q4 2025, image. Bar chart showing four quarters. Q1: 40 units…" The user hears the title immediately and can ask for the full description — the same progressive disclosure pattern used for image alt text vs. longdesc, but fully in-document.
For very large datasets (dozens of data points), even a thorough <desc> may not serve users well. In those cases, supplement the SVG with a real <table> element containing the underlying data — assistive technology handles tabular data natively and lets users navigate row by row.
Interactive SVG
SVG shapes like <rect> and <circle> are not natively interactive — they do not participate in tab order, do not fire keyboard events, and carry no role by default. If you add a click handler to a shape and nothing else, keyboard users and switch-access users are locked out completely.
The preferred approach: wrap with <button>
The simplest and most reliable fix is to put the interactive SVG content inside a real <button> element. Buttons are keyboard-focusable by default, fire on Enter and Space automatically, and carry the correct ARIA role without any extra attributes. The button's text content or an aria-label becomes the accessible name.
Note also that text rendered as SVG <path> outlines (outlines exported from a design tool) cannot be selected, copied, or read by AT. Prefer real SVG <text> elements — or real HTML text outside the SVG — whenever the text conveys information.
The fallback: tabindex + role + keyboard handler
When wrapping with a button is not feasible (e.g., deeply nested SVG components), you can make a shape directly focusable with three additions: tabindex="0" puts it in tab order, role="button" tells AT what it is, and a keydown handler that fires on Enter (key code 13) and Space (key code 32) replicates the native button keyboard contract. You must also add a visible :focus-visible style — SVG elements do not inherit the browser's default focus ring the way HTML form elements do.
Tab to the button and press Enter or Space — the circle toggles between green and red and the status message updates. The red outline defined in the page <style> block appears only on keyboard focus (via :focus-visible), so mouse users do not see an unwanted ring. The SVG inside the button carries aria-hidden="true" because the button's own aria-label already provides the accessible name — exposing the SVG internals separately would cause double-announcement.
Sufficient color contrast
WCAG 2.1 requires a contrast ratio of at least 4.5:1 for text and 3:1 for meaningful non-text graphics (like the border of a checkbox or the bars of a chart). Interactive controls add another requirement: their focus indicator must itself meet a 3:1 contrast ratio against adjacent colors. The red outline used in this demo (#d6452c against a white page) passes this threshold comfortably.
Do's and don'ts — quick summary
- Do add
role="img"and a<title>(as the first child) to every meaningful inline SVG. - Do add
aria-hidden="true" focusable="false"to purely decorative inline SVG. - Do supply
alt=""on<img src="…svg">when the image is decorative. - Do use
aria-labelledby+aria-describedbywith explicitidvalues for charts and diagrams that need both a name and a data summary. - Do wrap interactive SVG in a real
<button>— or addtabindex="0",role="button", and a keydown handler — and always write a:focus-visiblestyle. - Do use real SVG
<text>elements for text that conveys meaning; avoid converting text to path outlines in an export. - Don't rely on color alone to encode information — pair it with shape, pattern, or a text label.
- Don't skip accessible names on SVG icons that sit adjacent to visible text labels — those icons may still be read by AT if not hidden.