( Perceivable / WCAG 1.1.1 )

Image is missing alt text

CriticalLevel AWCAG 1.1.1 — Non-text Content

What is this issue?

An <img> element is missing its alt attribute entirely, or a functional image (one that’s the only content inside a link or button) has no accessible name from any source. The browser and assistive technology have no text to fall back on, so the image is either announced by its raw filename or skipped with no name at all, depending on the element and the screen reader.

This is distinct from an image that correctly uses alt="". An empty alt is a deliberate, valid instruction meaning “this image carries no information, skip it.” A missing alt attribute is an error state with no such instruction attached.

Why does this matter?

When a screen reader reaches an <img> with no alt attribute, it commonly reads out the filename, something like “hero-banner-final-v3, image”, because that’s the only text it has to work with. For a product photo, a chart, a diagram, or any image carrying information a sighted user gets for free, that filename conveys nothing.

The cost scales with what the image is doing. A missing alt on a decorative flourish is a minor miss. A missing alt on a chart showing quarterly revenue, a form’s only “required” indicator icon, or a product photo on an e-commerce listing removes content a sighted user relies on to make a decision: understand a trend, know a field is mandatory, judge whether to buy. The user isn’t inconvenienced; they’re working with less information than everyone else on the page.

Who is affected?

  • Screen reader users: hear a raw filename or the generic word “image” in place of the content the picture conveys, with no way to recover the missing information without asking someone else.
  • Cognitive disabilities: users who rely on images and icons as visual anchors while reading (a diagram next to a paragraph, an icon marking a warning) lose that supporting context when the image announces as noise instead of meaning.

What users experience

Daniel uses JAWS on Windows to compare laptops on an online electronics store. Each product card has a photo followed by a price, but the photos have no alt attribute. JAWS reads each one as “IMG_4471, graphic” before the price. Daniel can still read the specs and price, but has no way to judge the laptop’s actual condition or color from the listing (the one thing the photo was there to show him), so he opens a live chat to ask a question every other shopper on the page answered for themselves by looking.

How do I fix it?

Add an alt attribute to every <img>, and decide its value based on what the image is doing, not a blanket rule. This works because alt is the primary text alternative, a text description that conveys the same information as a non-text element so it works for people who can’t perceive the original, and every screen reader, browser, and search crawler already knows how to read it.

Start by classifying the image into one of four categories:

  • Informative: the image conveys specific content (a product photo, a headshot, an illustration). Write alt text that states what it shows: alt="Sarah Johnson, Head of Design", not alt="photo".
  • Decorative: the image adds visual polish but no information (a divider, a background flourish, a stock photo purely for mood). Use alt="" so screen readers skip it entirely instead of interrupting the page with something meaningless.
  • Functional: the image is the only content inside a link or button (a magnifying-glass search icon, a logo that links home). Describe the action, not the picture: alt="Search", not alt="magnifying glass icon".
  • Complex: the image carries more detail than a short phrase can hold (a chart, a diagram, an infographic). Write a short alt summarizing the takeaway, and put the full data in visible text nearby or a linked long description; don’t try to cram a paragraph into one attribute.

Code Examples

Before
<img src="/team/sarah.jpg">
<img src="/divider-wave.svg">
<a href="/search"><img src="/icons/magnifier.svg"></a>
After
<!-- Informative: describe what it shows -->
<img src="/team/sarah.jpg" alt="Sarah Johnson, Head of Design">

<!-- Decorative: empty alt so screen readers skip it -->
<img src="/divider-wave.svg" alt="">

<!-- Functional: describe the action, not the icon -->
<a href="/search"><img src="/icons/magnifier.svg" alt="Search"></a>

Each fix uses the same attribute but a different value, because the category determines what “correct” means. The informative image gets a description a sighted user would agree with. The decorative image gets nothing, on purpose. The functional image describes what happens when it’s activated, since that’s what a screen reader user needs to decide whether to click it; the icon’s visual appearance is irrelevant once it’s a control.

Framework Examples

Images in React are frequently rendered from an array of data fetched from a CMS or API, and it’s easy for a mapped list to render every photo with the right src but no alt if the source field doesn’t guarantee one. Fall back to an empty string explicitly rather than letting alt end up undefined, which some bundlers strip from the DOM entirely and leave equivalent to a missing attribute.

function ProductGallery({ products }) {
  return (
    <ul>
      {products.map((product) => (
        <li key={product.id}>
          <img
            src={product.photoUrl}
            alt={product.photoAlt ?? `${product.name} product photo`}
          />
        </li>
      ))}
    </ul>
  );
}

The ?? fallback matters because it guarantees every rendered <img> gets some alt text even when the CMS field is empty, rather than silently reintroducing this exact rule the moment one product record is missing data.

Common Mistakes

Mistake: “Decorative images don’t need alt, so I can just leave the attribute off.” Omitting the attribute and setting alt="" are not the same thing to a screen reader. Leaving it off is an error state that triggers a filename fallback in many screen readers; alt="" is the correct, deliberate way to mark an image as decorative and have it skipped cleanly.

Mistake: “Longer alt text is always more helpful.” For a screen reader user, alt text is read start to finish with no way to skim it the way a sighted user skims a photo. A paragraph-length description of a simple photo is slower and less useful than one accurate sentence; save the length for genuinely complex images like charts, and even then, keep the alt itself short and put full detail in visible nearby text.

Mistake: “A caption underneath the image already explains it, so alt text is redundant.” A visible caption has no programmatic connection to the image itself: a screen reader announces the image and the caption as two separate, unrelated pieces of content unless they’re explicitly connected (for example with <figure> and <figcaption>, and even then most screen readers still announce the <img> role separately). The image itself still needs its own alt.

Mistake: “SVGs don’t need alt text because they’re code, not a raster image.” An inline <svg> has no alt attribute, but it needs the equivalent accessible-naming treatment: role="img" with aria-label for an informative icon, or aria-hidden="true" for a decorative one. Skipping this because “it’s not an <img> tag” leaves the exact same gap this rule is about, just on a different element.

How RedFlag Detects This

Automated: axe-core rule, runs on every scan. RedFlag calls axe-core’s image-alt rule as part of every scan, restricted to the WCAG 2.0/2.1/2.2 A and AA rule set. The rule inspects every <img> element and checks whether it resolves a non-empty accessible name through alt, aria-label, aria-labelledby, or title, and separately confirms a decorative image using role="presentation" or role="none" is correctly paired with alt="".

False negative: axe-core confirms alt text exists; it cannot judge whether the text is accurate. alt="Team photo" on a revenue chart passes the automated check even though it describes the wrong thing entirely. Images set via CSS background-image are also outside this rule’s scope, since they aren’t <img> elements at all; a background image carrying real information is a silent gap no automated scan here catches. False positive: none typical for this check, since resolving to a non-empty accessible name (or a correctly empty one on a presentation image) is a binary condition axe-core evaluates reliably. Manual step: read every informative image’s alt text against the image itself and confirm it’s accurate, appropriately concise, and doesn’t just restate the filename in words.

Manual Testing

  1. Open the page in Chrome or Firefox with NVDA or VoiceOver running.
  2. Navigate through the page using the screen reader’s image-navigation shortcut (NVDA: Insert+F7 for the Elements List, filtered to Graphics; VoiceOver: the Rotor, filtered to Images).
  3. Listen to what’s announced for each image: it should be a specific, accurate description for informative images, complete silence (skipped) for decorative ones, and an action phrase for any image inside a link or button.
  4. If an image announces a filename, a generic word like “image” or “graphic” with nothing else, or a description that doesn’t match what’s actually shown, the check fails.
  5. For any image inside a link or button, confirm the screen reader announces a purpose (“Search,” “Go to homepage”) and not just the icon’s appearance.

1.1.1 Non-text Content: All non-text content must have a text alternative that serves the equivalent purpose. A missing alt attribute is the most direct possible failure of this criterion, since there’s no text alternative present at all.

4.1.2 Name, Role, Value: Every interface component must expose a name, role, and value. When a missing-alt image is the only content inside a link or button, that control also fails 4.1.2 on top of 1.1.1, since the image was the control’s only possible source of an accessible name.

Image map area is missing alt text and Image input is missing alt text cover the same missing-text-alternative failure on two other image-bearing elements axe-core checks separately from a plain <img>.

Alt text is a filename or placeholder and Alt text is a raw filename cover the next failure mode past this one: an alt attribute that exists but contains junk text instead of a real description, which RedFlag’s automated image-alt check alone cannot catch.

Object element has no text alternative is the equivalent naming failure for <object>-embedded content instead of <img>, sharing the same root cause of a missing text alternative.

Alt text repeats adjacent visible text is the opposite kind of quality problem: alt text that’s present and accurate but duplicates text already next to the image, adding noise instead of information.

References

Frequently asked questions

Do decorative images need alt text?

They need an empty alt attribute, written as alt="", not a missing one. Empty alt tells screen readers to skip the image entirely; a missing alt attribute makes most screen readers announce the filename instead, which is worse than saying nothing.

What is the difference between alt="" and no alt attribute at all?

alt="" is a deliberate instruction to skip the image, and screen readers respect it silently. A missing alt attribute is treated as an error state, and most screen readers fall back to announcing the image's filename or the word "image" so the user at least knows something is there.

Does RedFlag check whether alt text is accurate?

No. RedFlag confirms an alt attribute exists and is non-empty on informative images; it cannot judge whether the text actually describes the image correctly. A wrong-but-present description, like alt="Team photo" on a bar chart, passes the automated check.

Do CSS background images need alt text?

An alt attribute only exists on the HTML img element, so a CSS background-image has no alt to add. If a background image conveys real information, add that information as visible text or an aria-label on a nearby element instead, since it is invisible to screen readers otherwise.

Should alt text start with "image of" or "picture of"?

No. Screen readers already announce the element's role as "image" or "graphic" before reading the alt text, so prefacing it with "image of" makes the announcement redundant. Describe what the image shows, not the fact that it is an image.

Do SVG icons need alt text?

An inline SVG has no alt attribute, but the same informative-versus-decorative logic applies. Give an informative SVG an accessible name with a title element plus aria-labelledby, or role="img" with aria-label; hide a decorative SVG from the accessibility tree with aria-hidden="true".