Skip to content

Accessible Images and Icons — Complete Guide

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Accessible Images and Icons. We cover key concepts, practical examples, and best practices to help you master this topic.

Accessible images and icons require proper alt text strategies for different image types, SVG Accessibility patterns, icon font considerations, and responsive image techniques that serve all users regardless of device or ability.

What You'll Learn

  • Alt text strategies for different image contexts
  • Making SVGs accessible with role and aria-label
  • Icon font accessibility issues and alternatives
  • Responsive images with srcset and picture
  • CSS images and when to use img versus background-image

Why It Matters

  • Images and icons are everywhere on the web
  • Inaccessible images exclude blind and low-vision users
  • Icons without text labels are meaningless to screen reader users
  • Responsive images ensure usability across devices

Real-World Use

  • A weather app uses accessible weather icons with descriptions
  • A dashboard uses accessible SVG charts with fallback text
  • An e-commerce site uses responsive product images
  • A navigation uses icon + text label patterns
flowchart LR
  A[Visual Element] --> B{Type}
  B --> C[Informative Image]
  B --> D[Decorative Image]
  B --> E[Icon]
  B --> F[SVG Graphic]
  C --> G[Alt Text]
  D --> H[Null Alt]
  E --> I[Text Label]
  F --> J[role + aria-label]

Image Accessibility Patterns

Beyond basic alt text, images need consideration for context, responsiveness, and the medium through which they are delivered.

Context Matters for Alt Text

The same image needs different alt text in different contexts:

Context: E-commerce product page

alt="Handcrafted blue ceramic vase with white floral pattern, 12 inches tall, $45"

Context: Blog post about home decoration trends

alt="Blue ceramic vase with floral pattern on a pine wood table, surrounded by natural sunlight"

Context: Social media share

alt="Products: Handcrafted Blue Ceramic Vase"

SVG Accessibility

SVGs are inline graphics that can contain text. Unlike img elements, SVGs do not have implicit alt text. You must make them accessible explicitly.

Code Example: Accessible SVGs

<!-- Decorative SVG: hidden -->
<svg aria-hidden="true" focusable="false" width="24" height="24">
    <path d="M12 2L2 7l10 5 10-5-10-5z"/>
</svg>

<!-- Informative SVG with title -->
<svg role="img" aria-labelledby="warning-title" focusable="false" width="24" height="24">
    <title id="warning-title">Warning: Low battery</title>
    <path d="M12 2L1 21h22L12 2zm-1 7h2v6h-2V9zm0 8h2v2h-2v-2z" fill="#C62828"/>
</svg>

<!-- Linked SVG with visible text -->
<a href="/dashboard" class="nav-link">
    <svg aria-hidden="true" focusable="false" width="20" height="20">
        <rect x="2" y="2" width="8" height="8" rx="1" fill="currentColor"/>
        <rect x="12" y="2" width="8" height="8" rx="1" fill="currentColor"/>
        <rect x="2" y="12" width="8" height="8" rx="1" fill="currentColor"/>
        <rect x="12" y="12" width="8" height="8" rx="1" fill="currentColor"/>
    </svg>
    Dashboard
</a>

Expected output: Decorative SVGs are skipped by screen readers. Informative SVGs announce their title. Linked SVGs with visible text inherit the link's accessible name.

Code Example: Icon Fonts vs Inline SVGs

<!-- Icon font (problematic for accessibility) -->
<span class="icon icon-search" aria-hidden="true"></span>
<span class="icon-label">Search</span>

<!-- Inline SVG (more accessible) -->
<button aria-label="Search">
    <svg aria-hidden="true" focusable="false" width="20" height="20">
        <circle cx="8" cy="8" r="6" fill="none" stroke="currentColor" stroke-width="2"/>
        <line x1="12" y1="12" x2="18" y2="18" stroke="currentColor" stroke-width="2"/>
    </svg>
</button>

<!-- Icon + text pattern (most accessible) -->
<button>
    <svg aria-hidden="true" focusable="false" width="20" height="20">
        <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
    </svg>
    Search
</button>

Expected output: Icon fonts use CSS-generated content that may not be accessible to all screen readers. Inline SVGs with aria-hidden and adjacent text labels provide reliable accessibility. The icon + text pattern works for all users.

Code Example: Responsive Images

<!-- srcset for different screen sizes -->
<img src="photo-800.jpg"
     srcset="photo-400.jpg 400w,
             photo-800.jpg 800w,
             photo-1200.jpg 1200w"
     sizes="(max-width: 600px) 100vw,
            (max-width: 1024px) 50vw,
            33vw"
     alt="Mountain landscape at sunrise with snow-capped peaks">

<!-- picture element for art direction -->
<picture>
    <source media="(max-width: 600px)" srcset="photo-mobile.jpg">
    <source media="(max-width: 1024px)" srcset="photo-tablet.jpg">
    <img src="photo-desktop.jpg"
         alt="Team photo at the 2025 company retreat">
</picture>

<!-- High DPI display support -->
<img src="photo-1x.jpg"
     srcset="photo-1x.jpg 1x, photo-2x.jpg 2x, photo-3x.jpg 3x"
     alt="Product detail: handcrafted ceramic mug">

Expected output: The browser selects the appropriate image based on viewport size and device pixel ratio. All variants share the same alt text because the content is the same, just at different resolutions or crops.

Common Mistakes

  1. Icon-only buttons without accessible names — An icon button without aria-label or visible text is completely inaccessible. Screen readers may announce "button" with no context.
  2. Using CSS background-image for informative images — Background images are not in the accessibility tree. Informative images must be img elements with alt text.
  3. Missing focusable="false" on decorative SVGs — SVGs can receive focus in some browsers. Add focusable="false" and aria-hidden="true" for decorative SVGs.
  4. Icon fonts without aria-hidden — Icon fonts loaded via pseudo-elements can be announced by some screen readers. Always add aria-hidden="true" to icon font elements.
  5. Same alt text for different images — Every alt text must be unique and specific. "Product image" on 20 product pages provides no distinction.
  6. Not providing fallback for SVG — While rare, SVG failures happen. Consider adding a text fallback or using img with a PNG fallback inside a picture element.
  7. Spacer images — Using transparent GIFs for spacing is outdated. Use CSS margin and padding instead, and never include spacer images.

Practice Questions

  1. How do you make an inline SVG accessible? Add role="img" for informative SVGs, include a element or aria-label for the description, and add aria-hidden="true" for decorative SVGs.</li> <li>Why should icon fonts be avoided or handled carefully for accessibility? Icon fonts use CSS-generated content that may not be in the accessibility tree consistently across browsers and screen readers.</li> <li>What is the difference between srcset and the picture element? srcset provides different resolutions of the same image. picture provides different crops or aspect ratios (art direction) for different viewports.</li> <li>How should you handle a linked icon with text? The link text provides the accessible name. The icon inside the link should have aria-hidden="true" so the screen reader does not announce it separately.</li> <li>Challenge: Create an accessible weather widget that displays current conditions (temperature, humidity, wind) with icons. Use inline SVGs with proper aria attributes, text labels, and a fallback text description. Ensure the entire widget is keyboard navigable and screen reader accessible.</li> </ol> <h2 id="faq">FAQ</h2><p>{{< faq "Are icon fonts accessible?" "Icon fonts are not inherently accessible. They use CSS pseudo-elements which may not be exposed to the accessibility tree. If using icon fonts, add aria-hidden="true" to all icon elements and provide visible text labels." >}}</p> <details style="margin-bottom:12px;border:1px solid #e2e8f0;border-radius:10px;overflow:hidden"><summary style="cursor:pointer;padding:14px 18px;font-weight:600;font-size:1.05rem;background:#f8fafc;border-bottom:1px solid #e2e8f0;color:#1e293b">How do I make a responsive image accessible?</summary><div style="padding:14px 18px;color:#475569;line-height:1.7;background:#fff"><p>Use the img element with srcset and sizes attributes for resolution switching, or the picture element for art direction. All image sources must share the same alt text.</p> </div></details> {{< faq "Should I use img or background-image for decorative images?" "Use background-image in CSS for truly decorative images (they are not in the accessibility tree). Use img with alt=\"\" for decorative images in the HTML that are part of content flow." >}} {{< faq "How do screen readers handle SVGs?" "Screen readers handle SVGs differently. Some read the SVG as an image, some access the text content inside. Use role=\"img\" to ensure consistent treatment and provide an accessible name." >}} {{< faq "What is the best practice for a logo image?" "The logo should be an img element. If it is a link to the homepage, provide alt=\"Home\" or alt=\"Company Name Home\". If it is not a link, provide alt=\"Company Name\" as the site title." >}} <h2 id="mini-project">Mini Project</h2><p>Build an accessible icon system for a dashboard application. Create 6 icons (dashboard, users, settings, analytics, notifications, logout) using inline SVGs. Each icon must: have aria-hidden="true" when paired with visible text, use role="img" with a <title> when used standalone, set focusable="false" for decorative usage, and be styled with currentColor for theme support. Build a demo page that shows each icon in three contexts: standalone, icon + text label, and icon button with aria-label. Test with a screen reader.</p> <h2 id="whats-next">What's Next</h2><p>Continue with Lesson 17: Accessible Navigation and Menus to learn how to build navigation systems that work for all users.</p> </div> <div class="hx:mt-16"></div> <div class="hx:mb-8 hx:grid hx:grid-cols-2 hx:gap-4 not-prose"> <a href="/frontend/accessibility/15-data-tables/" class="hx:flex hx:flex-col hx:rounded-xl hx:border hx:border-gray-200 hx:p-4 hx:hover:border-primary-500 hx:transition-colors"> <span class="hx:text-xs hx:text-gray-500 hx:flex hx:items-center hx:gap-1">← Previous</span> <span class="hx:text-sm hx:font-medium hx:text-gray-700 hx:mt-1">Accessible Data Tables — Complete Guide</span> </a> <a href="/frontend/accessibility/17-navigation-menus/" class="hx:flex hx:flex-col hx:rounded-xl hx:border hx:border-gray-200 hx:p-4 hx:hover:border-primary-500 hx:transition-colors hx:text-right"> <span class="hx:text-xs hx:text-gray-500 hx:flex hx:items-center hx:gap-1 hx:justify-end">Next →</span> <span class="hx:text-sm hx:font-medium hx:text-gray-700 hx:mt-1">Accessible Navigation and Menus — Complete Guide</span> </a> </div> <div class="not-prose hx:mt-12 hx:p-6 hx:rounded-xl hx:border" style="background:linear-gradient(135deg,#fef2f2,#ffe4e6);border-color:#fecaca"> <div class="hx:flex hx:items-center hx:gap-3 hx:mb-3"> <div class="hx:w-10 hx:h-10 hx:rounded-lg hx:flex hx:items-center hx:justify-center hx:shrink-0" style="background:#ef4444;color:white"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg> </div> <div> <p class="hx:text-sm hx:font-semibold hx:m-0" style="color:#991b1b">Built by the developers of DodaTech</p> <p class="hx:text-xs hx:m-0" style="color:#b91c1c">Doda Browser, DodaZIP & Durga Antivirus Pro</p> </div> </div> <div class="hx:flex hx:flex-wrap hx:gap-2 hx:mt-3"> <a href="/" class="hx:inline-flex hx:items-center hx:rounded-full hx:px-3 hx:py-1.5 hx:text-xs hx:font-medium hx:transition-all" style="background:#fff;color:#dc2626;border:1px solid #fecaca">Home</a> <a href="/frontend/accessibility/" class="hx:inline-flex hx:items-center hx:rounded-full hx:px-3 hx:py-1.5 hx:text-xs hx:font-medium hx:transition-all" style="background:#fff;color:#dc2626;border:1px solid #fecaca">Browse Accessibility</a> <button onclick="window.print()" class="hx:inline-flex hx:items-center hx:rounded-full hx:px-3 hx:py-1.5 hx:text-xs hx:font-medium hx:cursor-pointer" style="background:#fff;color:#dc2626;border:1px solid #fecaca">Print</button> </div> </div> </main> </article> </div> <footer class="hextra-footer hx:bg-gray-100 hx:pb-[env(safe-area-inset-bottom)] hx:dark:bg-neutral-900 hx:print:bg-transparent"> <div class="hextra-custom-footer hextra-max-footer-width hx:mx-auto hx:pl-[max(env(safe-area-inset-left),1.5rem)] hx:pr-[max(env(safe-area-inset-right),1.5rem)] hx:text-gray-600 hx:dark:text-gray-400 hx:py-12"> <div class="hx:text-center hx:text-sm"> Built by the developers of <strong>Doda Browser</strong>, <strong>DodaZIP</strong>, and <strong>Durga Antivirus Pro</strong>.<br/> <span class="hx:text-xs">© 2026 DodaTech. All rights reserved.</span> </div> </div> </footer> <script defer src="/js/main.js"></script> <script defer src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script> <script>document.addEventListener('DOMContentLoaded',function(){mermaid.initialize({startOnLoad:true,theme:'neutral'})});</script> </body> </html>