Every image, icon button and chart needs a text alternative that does the same job; purely decorative images must be hidden from assistive technology.
A resident who is blind opens a county permit portal. The screen reader reads "link, plus dot png" where a button should be, then "graphic" four times where a site plan should be. The page has not failed to load; it has failed to describe itself.
WCAG 1.1.1 (Level A) says that all non-text content presented to the user needs a text alternative that serves the equivalent purpose. Text is the format that works across senses: it can be spoken, shown in braille, enlarged, translated or searched. The word that matters is equivalent purpose, not "literal description".
The criterion lists a handful of situations, each with its own expectation:
Imagine reading the page aloud to a friend over the phone. What would you say when you reached this image? The answer is the alt text. If the honest answer is "nothing, it is just a pretty border", the image is decorative and should be empty.
alt="", or a CSS background, so it is skipped.Do not begin with "image of" or "picture of"; the screen reader already announces the role.
Missing alt text appears on the Department of Justice's list of common web accessibility barriers, and it is easy to see why. Government sites accumulate images through years of manual uploads: council photos, scanned flyers pasted in as pictures, maps of polling places, budget charts exported as PNG files, and icon buttons in portals built by vendors.
The patterns that matter most are the ones that block a task. An icon-only "Renew" button with no name, a campground map that is the only place the accessible sites are shown, or a flyer image that carries the time and place of a public hearing leave a person without the information or the action. Because Title II points to WCAG 2.1 Level A and AA, a missing text alternative on a page a city or county provides is a plain gap against 1.1.1. See also the broader list of common barriers for how this fits with other frequent problems.
Start with controls, because an unnamed control is the most disruptive case. The name must describe the action.
<a href="/permits/new">
<img src="/img/plus-circle.png">
</a><a href="/permits/new">
<img src="/img/plus-circle.png"
alt="Start a building permit application">
</a>Complex images need two layers: a short name in the attribute and the real content in text a reader can reach.
<img src="pine-hollow-map.png" alt="map"><figure>
<img src="pine-hollow-map.png"
alt="Pine Hollow campground map, loops A to C">
<figcaption>
Accessible sites: A4, A9, B2 and C1.
<a href="/parks/pine-hollow/sites">Full site list</a>
</figcaption>
</figure>Decoration should be silent. An empty alt is a deliberate statement, not an omission.
<img src="wave-divider.png"
alt="decorative wave divider image"><img src="wave-divider.png" alt="">
<!-- or, better, keep it in CSS -->
.section-break { background: url(wave-divider.png) repeat-x; }Native apps have the same duty. In SwiftUI an icon-only button needs an explicit label, and purely decorative images should be marked as such.
Button(action: refreshArrivals) {
Image("refresh-arrows")
}Button(action: refreshArrivals) {
Image(decorative: "refresh-arrows")
}
.accessibilityLabel("Refresh bus arrivals")In Jetpack Compose, contentDescription = null on an icon inside a button removes the only name the control had. Put the description on the control that the user operates.
IconButton(onClick = { refreshArrivals() }) {
Icon(Icons.Default.Refresh, contentDescription = null)
}IconButton(onClick = { refreshArrivals() }) {
Icon(
Icons.Default.Refresh,
contentDescription = "Refresh bus arrivals"
)
}alt="IMG_4471.jpg".img, svg, image button and image map area has a deliberate text alternative or is deliberately empty.