Accessibility
Accessible SVG Icons: aria-label, role and the Rules That Matter
Make SVG icons accessible: when to hide decorative icons with aria-hidden, how to label icon-only buttons, title elements, focus states and WCAG 2.2 contrast rules.
Accessible SVG icons come down to one question: does this icon carry meaning, or is it decoration? Answer that honestly for every icon and the ARIA rules become simple. Get it wrong and screen-reader users hear either silence where information lives, or a stream of meaningless file names.
The decision framework: meaning, function or decoration
Sort every icon into one of three buckets before you write any ARIA. Decorative icons illustrate a label that already exists in text; they should be invisible to assistive technology. Functional icons are controls, or live inside controls; the control gets the name, and the icon itself is decorative inside it. Informative icons carry content nothing else carries, a status, a category, a warning; these need a text equivalent of their own. Most production bugs come from bucket confusion: a functional icon labelled as if it were informative, so the button ends up named twice, or an informative icon hidden as decoration, so its meaning vanishes for exactly the users who needed it.
- Ask what a user loses if the icon disappears. Nothing: decorative. The action: functional. Information: informative. Answer per icon, in context, not per icon file.
- The same glyph changes buckets by context. A warning triangle in a labelled alert banner is decorative; the same triangle alone in a table cell, signalling the row's status, is informative.
- When torn between decorative and informative, read the surrounding text aloud. If the sentence still makes sense without mentioning the icon, it was decorative.
- Record the decision in the component, not in a wiki. The next developer should inherit the bucket with the icon, not rediscover it.
Decorative icons: hide them properly
An icon beside a visible text label (a magnifier next to the word Search) adds nothing for a screen reader: the label already says it. Mark those icons aria-hidden="true" and focusable="false". This is most icons on most pages, including nearly every icon inside a labelled button.
<button>
<svg aria-hidden="true" focusable="false">...</svg>
Search
</button>Why both attributes, and what breaks with only one
aria-hidden removes the element from the accessibility tree, which is what screen readers traverse. focusable="false" handles a different layer: older browsers and some assistive setups could place keyboard or virtual focus on the SVG itself, stranding users on an element that announces nothing. Belt and braces costs nothing and prevents a class of bug that appears only in the exact browser and reader combination your automated tests do not run. Icon component libraries that set both by default when an icon is marked decorative are doing you a favour; verify yours does, because several popular ones historically set neither.
Edge cases: logos, linked images and icon-plus-text links
A logo inside a home link is functional: the link's name should be the destination or the brand, so the svg is hidden and the link carries an aria-label like the company name plus home, or visually hidden text saying the same. Social icons in a footer are the classic trap; a row of brand glyphs, each a link, each meaningless without a name. Give every link its network name (the platform, not follow us, which tells a screen-reader user nothing per item). Icon-plus-text links where the text is visible need no extra work at all: hide the icon, let the text name the link, and resist duplicating the name in an aria-label that will drift out of sync at the next copy edit.
Icon-only buttons: the button needs the name
When a button is only an icon (close, delete, settings), the accessible name belongs on the button, not the SVG: give the button an aria-label or visually hidden text. Labelling the SVG itself with role="img" and a title element is the right pattern only for standalone meaningful icons, like a status glyph in a table cell.
<button aria-label="Close dialog">
<svg aria-hidden="true">...</svg>
</button>Standalone meaningful icons: role img and the title element
When an icon stands alone as content, a status glyph in a table, a category marker in a list, it needs its own name, and the pattern is role="img" on the svg with a title element as its first child. The title inside an SVG with role img is what assistive technology announces; a title attribute on the svg element is a tooltip behaviour, inconsistently exposed, and is not a substitute. Give the title an id and reference it with aria-labelledby when you need the robust version of the pattern, which some screen reader and browser combinations handle more reliably than the bare title element.
<svg role="img" aria-labelledby="status-title">
<title id="status-title">Payment overdue</title>
<path d="..." />
</svg>Name the meaning, not the picture. The announcement should be payment overdue, not red triangle, because the user needs the information the sighted user extracts from the glyph, and colour plus shape were only ever the encoding. This rule, name the message, resolves most labelling debates: a star icon meaning favourite gets the name favourites or add to favourites depending on whether it informs or acts, and a checkmark confirming success is named completed, never green check.
How accessible names are actually computed
Browsers compute a control's name from a priority list: aria-labelledby beats aria-label, which beats the element's own text content, which beats title attributes and placeholders. Knowing the order explains the classic bugs. Visible text inside a button names it automatically, so an aria-label added for insurance overrides the visible text with something that may contradict it, a failure for voice-control users who say what they see and get no match. An icon labelled with role img inside a button contributes its title to the button's name computation in some engines, producing doubled names like close close dialog. The hygiene rules follow directly: one naming source per control, prefer visible text, use aria-label only when no visible text exists, and keep the icon itself silent inside controls.
Contrast and target size (WCAG 2.2)
- Meaningful icons need 3:1 contrast against their background (WCAG non-text contrast).
- Interactive icons need a target of at least 24 by 24 CSS pixels, and 40+ is kinder on touch devices.
- Never use colour alone: pair status icons with a shape or label difference (check vs cross, not just green vs red).
- Focus indicators must remain visible on icon buttons; do not remove outlines without a replacement.
WCAG 2.2 criteria, mapped to icon work
- 1.1.1 Non-text Content (A): every informative icon has a text alternative serving the same purpose; decorative icons are hidden so they need none. This is the criterion the bucket framework exists to satisfy.
- 1.4.1 Use of Color (A): colour is never the only channel. A status system that differs only in hue fails; add shape, position or a label so the information survives colour-blindness and greyscale printing.
- 1.4.11 Non-text Contrast (AA): meaningful icons and the boundaries of interactive icon controls need 3:1 against adjacent colours. Check icon against its button background, not against the page, and check the unfocused default state, not just hover. The contrast checker settles arguments in seconds.
- 2.4.7 Focus Visible (AA): keyboard focus on an icon button must show. Custom icon controls that remove outlines for aesthetics are a per-se failure unless a replacement indicator meets contrast rules too.
- 2.5.8 Target Size Minimum (AA, new in 2.2): pointer targets are at least 24 by 24 CSS pixels, with spacing exceptions; icons in dense data tables are the common casualty, and the fix is padding, not a bigger glyph.
- 4.1.2 Name, Role, Value (A): custom icon controls built on divs and spans must expose button role, a name and state (expanded, pressed, selected) programmatically, or be rebuilt as real buttons, which is usually less work.
- 1.4.4 and 1.4.10 Resize and Reflow (AA): icons must survive 200 percent zoom and 320 pixel wide viewports without loss; vector icons pass the rendering half of this trivially, and layouts fail the other half when icon rows refuse to wrap.
Testing: what to actually run
Automated checkers catch the mechanical failures, missing names, missing alt equivalents, contrast below threshold, and they should run in CI like any other test. They cannot judge whether a name is good, only whether one exists, so pair them with three manual passes. The keyboard pass: unplug the mouse metaphorically and tab through the page, confirming every icon control is reachable, visibly focused and operable with Enter, Space and arrows where the pattern promises them. The screen-reader pass: with a reader running, navigate by buttons and by graphics and listen for silence where decoration lives and clear names where meaning lives; doubling and file names are obvious the moment you hear them. The zoom pass: at 200 and 400 percent, confirm icon rows wrap or scroll intentionally and that no meaning depends on an icon that has been pushed off-screen.
- Test with at least one real screen reader pairing (for example NVDA with Chrome or VoiceOver with Safari); emulated accessibility trees miss announcement behaviour.
- Navigate by graphic and by button in the reader and diff the lists against what a sighted user sees; every mismatch is a bug report.
- Voice-control check: speak the visible label of ten icon controls. Any that fail to activate have a name-versus-label mismatch, usually an aria-label overriding better visible text.
- Test in forced-colors mode (Windows High Contrast) at least once per design-system release; it is where icon assumptions go to die.
Forced colours, dark mode and motion
Windows forced-colors mode replaces your palette with the user's, and icons drawn with hard-coded fills can vanish entirely against forced backgrounds, while currentColor icons adapt automatically because they were never really coloured by you. This is a strong engineering argument for the theming discipline the rest of this site recommends: inherit colour, and platform accessibility features work for free. Dark mode has its own version of the trap: a dark icon on a transparent background that was designed against a light card disappears when the card inverts; currentColor prevents it, baked-in fills guarantee it eventually. Motion completes the picture: animated icons, spinners excepted, must respect prefers-reduced-motion with a static end state, and no information may be conveyed by animation alone, because the users who disable motion are telling you the movement itself is the barrier.
A pull-request checklist for icon changes
- Every new icon sorted into decorative, functional or informative, with the treatment matching the bucket.
- Decorative icons carry aria-hidden and focusable false, set by the component, not remembered by the author.
- Icon-only controls named on the control, with the name matching or including the visible label if one exists.
- Informative icons named for their meaning, never for their shape or colour.
- Contrast verified for the icon against its actual background at 3:1, including disabled states that still convey information.
- Targets at least 24 by 24 CSS pixels and comfortably larger on touch layouts; focus indicator visible and not colour-only.
- No icon conveys status by colour alone; shape or text differs too.
None of this requires special tooling: it is a review habit. When you pick icons from a set like Lucide or Phosphor on IconVault, decide decorative versus meaningful as you place each one. Our SVG icons in buttons and navigation patterns in the main usage guide show the labelled patterns in context.
Do icon libraries handle accessibility for you?
Partly, and the boundary matters. Good component libraries render icons as decorative by default, applying aria-hidden, because most icons in most interfaces are decorative, and that default quietly fixes the majority case. What no library can know is your context: whether this particular glyph is the only carrier of a status, whether the button it sits in already has visible text, whether the link it decorates has a name anywhere. Libraries also differ in their defaults and have changed them across versions, so an upgrade can silently alter the accessibility tree of every screen. Treat the library default as a starting hypothesis, verify it in your own rendered output, and own the bucket decision in your components. When you copy individual icons from a set through the app rather than installing a package, you own the defaults entirely, which is more work and more certainty in equal measure.
Failure patterns that show up in real audits
- The narrated toolbar: a header where every icon is exposed as an unnamed graphic, so a screen reader announces image, image, image across the primary navigation. Cause: icons rendered as content images with no hiding and no names. Fix: the bucket pass, top to bottom.
- The lying label: an aria-label copied from a design file says share, while the visible tooltip and the actual behaviour say copy link. Voice users say share and nothing happens. Cause: naming sources drifting. Fix: one source, matching the visible label.
- The invisible focus: icon buttons in a custom toolbar show focus by removing the outline and changing nothing else. Keyboard users are navigating blind. Fix: a designed focus state meeting contrast requirements, tested by actually tabbing.
- The colour-only status column: a table where paid, pending and failed differ only in icon colour, all three the same checkmark shape. Screen readers get silence and low-vision users get a guessing game. Fix: distinct shapes plus a text status, which also helps every sighted user scanning quickly.
- The 24-pixel glyph in a 24-pixel world: dense grids where the clickable area is the glyph itself, failing target-size minimums and frustrating motor-impaired users. Fix: padding on the control; the artwork does not change at all.
Writing names users can act on
Accessible names are microcopy, and they reward the same discipline. Use the verb the interface uses elsewhere: if the menu item says Download report, the icon button is Download report, not Save, not Export, and not the designer's nickname for the feature. Keep names as short as the visible system allows, because screen-reader users hear them in lists and in search-style navigation where long names blur together. Never include the word icon, image or graphic in a name; the role already announces the element type, and icon is the written equivalent of saying the word picture aloud after every noun. Finally, keep names stable across releases unless the function itself changes; users build muscle memory around names in voice control and reader navigation, and a whimsical rename is a breaking change wearing a copy edit as a disguise.
Icons in forms and error states
Forms concentrate every icon mistake into one screen. The error icon beside a field is decorative if the error text is properly associated with the input, and harmful noise if it is exposed as an unnamed image between the label and the message the user actually needs. Required-field asterisks rendered as icons must be hidden, with required communicated by the input's own attributes, because a screen reader announcing star is a riddle, not a requirement. Success checkmarks after validated fields follow the same rule: the state belongs in the field's programmatic status or in a live message, not in a glyph. Get forms right and you have usually fixed the highest-stakes icons on the site, since forms are where users transact, err and recover.
Before and after: one toolbar, fixed
Consider a document toolbar as typically shipped: a save icon exposed as an unnamed image, a trash icon whose button is labelled delete-icon by its file name, a settings gear announced as graphic, and a share button labelled export because the designer renamed the feature in the label but not the code. A screen-reader user hears a parts list. After the bucket pass, the glyphs are hidden, the buttons are named Save, Delete, Settings and Share to match the tooltips a sighted user sees, the one informative glyph, a sync status, carries its state as text, and the toolbar announces as five clear actions and one clear status. No icon changed. No visual pixel moved. The entire improvement is semantic, which is why accessibility work on icons is the highest-leverage hour most frontend teams can spend.
If the scale of this feels daunting, start where users feel it most: the primary navigation, the main toolbar of your core workflow, and your forms. Those three surfaces carry the overwhelming majority of icon interactions, and an afternoon spent sorting their icons into buckets, naming their controls and checking their contrast fixes the experience most users, assistive technology or not, will judge the whole product by. The long tail of settings screens and footers can follow the same checklist sprint by sprint, and each pass gets faster because the patterns, and the component defaults that encode them, are already decided. Accessibility debt on icons rarely comes from ignorance of the rules; it comes from the rules never being written into the components. Write them in once, and the accessible choice becomes the path of least resistance for every icon anyone adds afterwards.
How to make SVG icons accessible: the complete workflow
Start with the bucket decision, not with attributes. How to make SVG icons accessible begins with sorting every icon into decorative, functional or informative, because the bucket decides the treatment and the treatment decides the markup. When teams learn how to make SVG icons accessible as a workflow, the first step is always that sorting pass, and accessible SVG icons result from it naturally: decorative glyphs get hidden, functional glyphs lend their meaning to their controls, and informative glyphs get names of their own. A team that ships accessible SVG icons treats the bucket decision as a review habit, recorded in the component, so the next developer inherits accessible SVG icons rather than rediscovering the rules. That habit, repeated across navigation, toolbars and forms, is what turns accessible SVG icons from a checklist into a property of the product.
The workflow continues with naming, contrast and testing, in that order. Name every control once, from one source, preferring visible text and using aria-label only where no visible text exists. Check contrast of meaningful glyphs against their actual backgrounds at 3:1, and check targets at 24 by 24 pixels minimum, because accessible SVG icons fail audits most often on these mechanical points rather than on exotic ARIA. Then test with a real screen reader, a keyboard pass and a zoom pass, since automated checkers catch missing names but cannot judge whether a name is good. Teams that run how to make SVG icons accessible through this loop, sort, name, check, test, ship accessible SVG icons that survive audits and, more importantly, serve users, and how to make SVG icons accessible should be taught to every new frontend hire as part of onboarding. The loop gets faster every release because the component defaults encode the decisions, and accessible SVG icons stay accessible only while the loop runs. That is the whole workflow: accessible SVG icons are not a feature to add, they are the result of a loop the team runs.
Accessible SVG icons in navigation and toolbars
Navigation is where accessibility failures are loudest. A header full of unnamed graphics announces to a screen reader as image, image, image across the primary navigation, which is the single most common icon failure in real audits. When you plan how to make SVG icons accessible in navigation, hide every decorative glyph beside a visible label, and name every icon-only control on the control itself, matching the visible tooltip word for word. Accessible SVG icons in navigation follow one rule above all: the announced name must equal the visible label, because voice-control users say what they see and get no match otherwise. Teams that audit accessible SVG icons in navigation first fix the surface users touch most, and accessible SVG icons in toolbars follow the same rule, since a toolbar is navigation with denser spacing and higher stakes.
Toolbars add two complications: density and state. Dense toolbars tempt teams to shrink targets below the 24-pixel minimum, and the fix is padding on the control, not a bigger glyph, so accessible SVG icons keep their artwork while their targets grow. State is the second complication: a toggle button must expose its pressed state programmatically, and a selected tab must expose its selected state, because accessible SVG icons that change appearance without changing their announced state lie to assistive technology. Test toolbars by tabbing through them without a mouse, listening for clear names and visible focus, and checking that how to make SVG icons accessible in toolbars survives translation, since a German label that overflows can push controls into wrapping or clipping. A toolbar whose accessible SVG icons pass that test will pass almost any audit, and the test takes minutes.
How to make SVG icons accessible in forms and error states
Forms concentrate every icon mistake into one screen. How to make SVG icons accessible in forms starts with the error icon beside a field: decorative if the error text is properly associated with the input, and harmful noise if exposed as an unnamed image between the label and the message the user actually needs. When you learn how to make SVG icons accessible in forms, the same rule covers required-field asterisks, which must be hidden while required is communicated by the input's own attributes, because a screen reader announcing star is a riddle, not a requirement. Accessible SVG icons in forms therefore follow the bucket framework strictly, and accessible SVG icons in error states earn their keep when the state lives in the field's programmatic status or a live message, not in a glyph. Get forms right and you have usually fixed the highest-stakes accessible SVG icons on the site, since forms are where users transact, err and recover.
Success states deserve the same care. A checkmark after a validated field should not be the only carrier of success, because the state belongs in the field's status or a live region that announces the change. Password visibility toggles, date pickers and file uploads each add their own icon controls, and each needs a name, a visible focus indicator and a target of at least 24 pixels, which is why how to make SVG icons accessible in forms is best handled by a form component library that encodes these patterns once. Teams that build accessible SVG icons into their form components, rather than bolting them on per form, find that every new form inherits the right behaviour, and accessible SVG icons in forms stop being a review topic at all. That is the goal: forms so consistently accessible that nobody discusses them.
Accessible SVG icons and colour: never colour alone
Colour is never the only channel. A status system that differs only in hue fails users with colour blindness and fails greyscale printing, so accessible SVG icons pair every colour difference with a shape, position or label difference: check versus cross, not just green versus red. When you design how to make SVG icons accessible for status, the test is simple: print the screen in greyscale, and if the statuses are still distinguishable, the design passes. Accessible SVG icons that pass the greyscale test also help every sighted user scanning quickly, because shape differences are faster to read than hue differences at a glance. The same principle covers charts, badges and progress indicators, where accessible SVG icons must carry their meaning in geometry, not just in palette, and the design system should enforce it with a rule, not a reminder.
Contrast is the numeric half of the colour story. Meaningful icons need 3:1 against adjacent colours under WCAG criterion 1.4.11, measured in the default state against the actual background, not against the page and not on hover. Ghost buttons with faint icon-only affordances fail this constantly, because the icon is the control's only visible boundary and that boundary is too faint to see. Check accessible SVG icons against their button backgrounds with a contrast tool, including disabled states that still convey information, and remember that purely decorative icons are exempt, which is one more reason to sort buckets honestly. Teams that verify how to make SVG icons accessible for contrast with a tool, rather than by eye, settle arguments in seconds and ship accessible SVG icons that pass audits without drama.
How to make SVG icons accessible for keyboard and voice users
Keyboard and voice users expose naming failures that mouse users never see. How to make SVG icons accessible for keyboard users means every icon control is reachable by tab, visibly focused, and operable with Enter, Space or arrows where the pattern promises them, with a focus indicator that meets contrast rules and is never removed without a replacement. When you learn how to make SVG icons accessible for voice users, the rule is stricter: the accessible name must match the visible label, because a user who says the label they see must activate the control they mean. Accessible SVG icons that satisfy both groups share one property: a single naming source per control, visible text preferred, aria-label only where no visible text exists. Teams that test accessible SVG icons with keyboard-only navigation and a voice-control pass catch the lying labels and invisible focus states that automated checkers miss entirely.
Custom icon controls deserve special suspicion. A div with a click handler is not a button, no matter how it looks, and it must expose button role, a name and state programmatically, or be rebuilt as a real button, which is usually less work. Focus management matters too: when an icon button opens a dialog or a menu, focus must move into the new surface and return to the button on close, or keyboard users are stranded. These behaviours are part of how to make SVG icons accessible for keyboard users, and they are also part of good engineering generally, which is why accessible SVG icons are rarely a separate workstream in mature teams. Build the controls correctly, name them once, show focus always, and accessible SVG icons follow as a consequence rather than a campaign.
Accessible SVG icons in data tables and status lists
Tables are where informative icons hide. A warning triangle alone in a table cell, signalling a row's status, is informative, while the same triangle in a labelled alert banner is decorative, and the bucket changes with context, not with the file. When you plan how to make SVG icons accessible in tables, give every status glyph a text equivalent of its meaning, payment overdue rather than red triangle, because the user needs the information the sighted user extracts from the glyph, and colour plus shape were only ever the encoding. Accessible SVG icons in tables also need row-level sense: a screen-reader user navigating by rows should hear the status as part of the row, not as an orphaned graphic between cells. Teams that sort accessible SVG icons in tables by meaning, not by file, fix the column that audits flag most, and accessible SVG icons in status lists follow the identical rule.
Status lists, notification feeds and activity timelines share the table's problem at a smaller scale. Each item pairs a glyph with a message, and the glyph is decorative only when the message already carries the meaning; when the glyph is the only carrier, it needs its own name through role img and a title element describing the meaning. The naming rule, name the message, resolves most debates: a star meaning favourite becomes favourites or add to favourites depending on whether it informs or acts, and a checkmark confirming success becomes completed, never green check. How to make SVG icons accessible in lists is therefore a writing problem as much as a markup problem, and the best test is to read the list aloud without the icons: if it still makes sense, the icons were decorative, and if it does not, the missing sentences are the names the icons need. Accessible SVG icons in lists that pass that test read clearly to everyone.
Testing accessible SVG icons with real assistive technology
Automated checkers catch mechanics, not meaning. They catch missing names, missing alt equivalents and contrast below threshold, and they should run in CI like any other test, but they cannot judge whether a name is good, only whether one exists. Real testing of how to make SVG icons accessible therefore pairs automation with three manual passes: the keyboard pass, tabbing through every icon control and confirming reachability, visible focus and operability; the screen-reader pass, navigating by buttons and by graphics and listening for silence where decoration lives and clear names where meaning lives; and the zoom pass, confirming at 200 and 400 percent that icon rows wrap or scroll intentionally and no meaning depends on a glyph pushed off-screen. Accessible SVG icons that pass all three passes are genuinely usable, and accessible SVG icons that pass only automation are merely plausible, which is a difference audits increasingly detect.
Test with at least one real screen reader pairing, such as NVDA with Chrome or VoiceOver with Safari, because emulated accessibility trees miss announcement behaviour, including the doubled names that occur when a button and its inner SVG both expose titles. Navigate by graphic and by button in the reader and diff the lists against what a sighted user sees; every mismatch is a bug report. Add a forced-colors mode pass at least once per design-system release, since Windows High Contrast replaces your palette and hard-coded fills can vanish entirely, while currentColor icons adapt automatically. Teams that test how to make SVG icons accessible this way, with real tools on real surfaces, find that accessible SVG icons stop being scary, because the failures become specific, fixable and few, and each release gets easier than the last.
Accessible SVG icons in design systems and component libraries
Component defaults are where accessibility scales or dies. A library that renders icons as decorative by default, applying aria-hidden, quietly fixes the majority case, because most icons in most interfaces are decorative. What no library can know is your context: whether this particular glyph is the only carrier of a status, whether the button it sits in already has visible text, whether the link it decorates has a name anywhere. When you adopt a library, verify its defaults in your own rendered output, because libraries differ in their defaults and have changed them across versions, so an upgrade can silently alter the accessibility tree of every screen. How to make SVG icons accessible at design-system scale therefore means owning the bucket decision in your components, encoding it in props, and treating the library default as a starting hypothesis, not a guarantee. Accessible SVG icons built this way survive upgrades, because the decisions live in your code, not in a dependency's changelog.
The component API should make the accessible choice the easy choice. A wrapper that accepts either a title for meaningful icons or a decorative flag that applies aria-hidden and focusable false together prevents call sites from setting one and forgetting the other. Document the bucket decision per component, not in a wiki: the next developer should inherit the treatment with the icon, not rediscover it. When you copy individual icons from a set through the app rather than installing a package, you own the defaults entirely, which is more work and more certainty in equal measure. Teams that build accessible SVG icons into their wrappers, their reviews and their tests find that accessibility stops being a gate at the end and becomes a property of the system, and properties of the system are what scale. That is how to make SVG icons accessible across a whole product: encode the rules once, and let every icon anyone adds afterwards inherit them.
Accessible SVG icons: a pre-ship checklist
A checklist beats a review meeting, and this one fits on a card. Every new icon sorted into decorative, functional or informative, with the treatment matching the bucket. Decorative icons carrying aria-hidden and focusable false, set by the component, not remembered by the author. Icon-only controls named on the control, with the name matching or including the visible label if one exists. Informative icons named for their meaning, never for their shape or colour. Contrast verified for the icon against its actual background at 3:1, including disabled states that still convey information. Targets at least 24 by 24 CSS pixels and comfortably larger on touch layouts, with a focus indicator visible and not colour-only. No icon conveying status by colour alone; shape or text differs too. Teams that run how to make SVG icons accessible through this checklist before every release catch the failures that audits charge for, and accessible SVG icons shipped under this checklist rarely surprise anyone.
Keep the checklist where the work happens: in the pull-request template, not in a document nobody opens. A checklist item per release, icons sorted, controls named, contrast checked, targets sized, focus visible, turns accessibility review into a minute of ticking boxes rather than an hour of debate. When a new surface launches, run the checklist against its primary navigation, its main toolbar and its forms first, because those three surfaces carry the overwhelming majority of icon interactions, and the long tail of settings screens and footers can follow sprint by sprint. How to make SVG icons accessible, done this way, becomes ordinary engineering hygiene, and ordinary hygiene is the only kind that lasts. Ship accessible SVG icons under this checklist, and the next audit will read like a confirmation, not a discovery.
Accessible SVG icons for mobile apps and touch interfaces
Touch interfaces raise the stakes for naming and targets. How to make SVG icons accessible on mobile starts with targets: at least 24 by 24 pixels, and 40 or more on touch layouts, because a 24-pixel glyph in a 24-pixel world frustrates motor-impaired users and fails audits. When teams learn how to make SVG icons accessible for touch, the second lesson is that tooltips do not exist: a tooltip is not an accessible name, it does nothing for touch users, and it vanishes for voice-control targeting, so name the control properly and keep the tooltip as decoration that agrees with the name. Accessible SVG icons on mobile therefore need names on controls, targets with padding, and focus indicators that survive small screens, and accessible SVG icons that meet those three tests serve every mobile user, and accessible SVG icons on tablets share the same rules, because touch is touch at any screen size. The same discipline that makes accessible SVG icons pass desktop audits makes accessible SVG icons usable on phones, and how to make SVG icons accessible on mobile is mostly the desktop workflow with larger targets and no tooltips. Teams that test how to make SVG icons accessible on real phones, with real thumbs, catch the failures emulators hide. Ship accessible SVG icons with padding, not bigger artwork, and the artwork never has to change.
Native apps replay the same rules with platform accents. iOS and Android design systems accept SVG-derived assets through their own pipelines, and both impose opinions about fills, strokes and unsupported features, so test the conversion rather than trusting it. How to make SVG icons accessible in native apps means checking that the platform's accessibility tree receives the same names the web version announces, because a glyph that is decorative on the web must not become an unnamed image in the app. When teams document how to make SVG icons accessible across platforms, the document should name the bucket per icon, not per platform, since meaning does not change when the renderer does. Accessible SVG icons in native apps follow the same bucket framework, and accessible SVG icons that change buckets between platforms confuse users who switch devices. Accessible SVG icons in hybrid apps inherit the web rules, since the renderer is a web view with platform chrome. The practical test is simple: run how to make SVG icons accessible through the platform's own inspector, compare the tree with the web tree, and fix every mismatch, because accessible SVG icons must announce consistently everywhere, and how to make SVG icons accessible consistently is the standard users deserve. Ship accessible SVG icons with platform-tested names, and the cross-device experience stays coherent, because accessible SVG icons are a cross-platform promise, not a per-platform accident.
Reduced motion and dark mode complete the mobile picture. Animated icons must respect prefers-reduced-motion with a static end state, and no information may be conveyed by animation alone, because the users who disable motion are telling you the movement itself is the barrier. Dark mode has its own trap: a dark icon on a transparent background designed against a light card disappears when the card inverts, while currentColor icons adapt automatically. Accessible SVG icons on mobile must respect both motion and theme, and the test is a real device. How to make SVG icons accessible in dark mode therefore means inheriting colour, and how to make SVG icons accessible with reduced motion means shipping the static end state as a first-class design, not an afterthought. Accessible SVG icons that respect motion preferences and theme changes serve users whose needs are invisible to the team, and accessible SVG icons that ignore them fail quietly. Test both on a real device, because how to make SVG icons accessible on mobile is proven on hardware, not in emulators, and accessible SVG icons proven on hardware stay proven. Ship accessible SVG icons that adapt, and adaptation stops being a feature request. The checklist for mobile is short: targets, names, motion, theme, and accessible SVG icons that pass all four pass everywhere.
A final note on ownership: somebody must own the checklist, or it rots. Name an owner for accessible SVG icons in your team, review accessible SVG icons in every major release, and keep accessible SVG icons on the definition of done for new surfaces. When accessible SVG icons have an owner, they stay fixed; when they do not, they drift, and drift is how audits surprise you.
Frequently asked questions
Should every SVG icon have an aria-label?
No, and adding one to every icon creates the noise problem this guide exists to prevent. Decorative icons get no label and are hidden with aria-hidden. Icons inside controls get no label either; the control carries the name. Only standalone informative icons get their own naming, through role img and a title element describing the meaning.
What is the difference between aria-hidden and an empty alt for icons?
They are the same idea in different syntaxes. An img element uses an empty alt attribute to declare itself decorative; an inline SVG has no alt attribute, so aria-hidden true plus focusable false achieves the identical result, removing it from the accessibility tree. Using the img pattern on inline SVG, or hunting for an alt attribute that does not exist there, is a common beginner confusion.
My icon button reads out twice. What went wrong?
Almost always a doubled naming source: the button has an aria-label and the SVG inside it also exposes a title, or the button wraps visible text that already names it while an aria-label overrides with near-identical words. Keep exactly one source. Hide the icon, name the button once, and the announcement becomes the single clean label you intended.
How much contrast does an icon need under WCAG 2.2?
A meaningful icon needs at least 3:1 against adjacent colours under criterion 1.4.11, measured in its default state against its actual background. Purely decorative icons are exempt. If an icon functions as a control's only visible boundary, that boundary needs the same 3:1, which is why ghost buttons with faint icon-only affordances so often fail audits.
Are tooltips an accessible name for icon buttons?
No. A tooltip is a visual supplement that appears on hover or focus; it is not reliably exposed as the control's accessible name, it does nothing for touch users, and it vanishes for voice-control targeting. Name the button properly with aria-label or hidden text, and keep the tooltip, if you like it, as decoration that agrees with the name.
Find the icons from this guide
Search 421,020 free SVG icons from 239 libraries in one place.