Image alt text serves two audiences: screen readers (accessibility) and search engines (SEO). Done well, the same alt text serves both. Done badly — empty, missing, stuffed with keywords, or pasted from filename like IMG_2342 — it fails both. This guide covers writing alt that describes images accurately, the four image roles and how each gets treated differently, and the templating fixes that make good alt the default for every new image.
# Count images missing alt on the homepage curl -s https://yoursite.com/ | grep -oE '<img[^>]*>' | grep -v 'alt=' | wc -l # Find duplicate alt values curl -s https://yoursite.com/ | grep -oE 'alt="[^"]+"' | sort | uniq -c | sort -rn | head
Different roles get different alt treatment:
Images that add nothing the user needs to know — visual dividers, background patterns, icons next to a text label saying the same thing.
<img src="divider.svg" alt=""> <img src="check-icon.svg" alt=""> Available now <!-- Or for CSS-decorative: --> <img src="hero-bg.jpg" alt="" role="presentation">
Images that convey information not present in text. Product photos, charts, illustrations of concepts.
<img src="widget-blue.jpg" alt="Blue ceramic widget with brushed steel base"> <img src="conversion-chart.png" alt="Conversion rate rose from 2.1% to 4.8% after redesign">
Images that are buttons, links, or trigger an action. Describe what happens, not what the image looks like.
<a href="/pricing.html"> <img src="cart-icon.svg" alt="View cart"> </a> <!-- NOT alt="shopping cart icon" — describes appearance, not function --> <button> <img src="search.svg" alt="Search"> </button>
Charts, graphs, infographics with rich data. Short alt summarises; details go in a caption or surrounding text.
<figure>
<img src="quarterly-revenue.png"
alt="Quarterly revenue from 2022 to 2024, detailed breakdown below">
<figcaption>
Revenue grew steadily through 2022 ($1.2M to $1.8M),
accelerated in 2023 ($2.1M to $3.4M), and reached $4.1M in Q4 2024.
</figcaption>
</figure>
<img src="..." alt="image"> <img src="..." alt="photo"> <img src="..." alt="IMG_2342"> <img src="..." alt="blue product">
<img src="widget.jpg" alt="best blue widget cheap blue widget buy blue widget online blue widget review blue widget for sale">
<img src="widget.jpg" alt="Blue ceramic widget with brushed steel base, 12cm tall"> <img src="team.jpg" alt="Five-person engineering team standing in front of whiteboard"> <img src="exercise.jpg" alt="Demonstration of proper deadlift form, hips hinged, back straight">
alt="" (attribute present, no value) is different from missing alt attribute entirely. Screen readers skip empty alt. Missing alt → they read the filename, which is usually meaningless.<!-- Correct: screen reader skips --> <img src="divider.svg" alt=""> <!-- Wrong: screen reader reads 'image divider dot S V G' --> <img src="divider.svg">
Image filenames also signal context to search engines. Descriptive filenames > camera-generated names.
<!-- Bad --> <img src="/uploads/IMG_2342.jpg" alt="..."> <img src="/uploads/DSC_0001.jpg" alt="..."> <img src="/uploads/screenshot 2024-01-15 at 14.32.55.png" alt="..."> <!-- Good --> <img src="/uploads/blue-ceramic-widget.jpg" alt="..."> <img src="/uploads/2024-conference-keynote.jpg" alt="..."> <img src="/uploads/dashboard-revenue-view.png" alt="...">
Use lowercase, hyphens between words, no spaces, no underscores, descriptive of the image content.
Don't fix images one at a time. Fix the templates so future uploads default to descriptive alt.
// functions.php — flag images missing alt
function require_image_alt($attachment_ID) {
$alt = get_post_meta($attachment_ID, '_wp_attachment_image_alt', true);
if (empty($alt)) {
// Use post title as fallback
$title = get_the_title($attachment_ID);
update_post_meta($attachment_ID, '_wp_attachment_image_alt', $title);
}
}
add_action('add_attachment', 'require_image_alt');
// .eslintrc.js
{
"rules": {
"jsx-a11y/alt-text": "error"
}
}
// TypeScript — alt is required, not optional
interface ImageProps {
src: string;
alt: string; // not alt?: string
width?: number;
height?: number;
}
// Decorative images explicitly opt-in
interface DecorativeImageProps {
src: string;
decorative: true; // forces explicit decoration choice
width?: number;
height?: number;
}
Modern image-to-text models can suggest reasonable alt text. Use them to seed initial alt, then human-review for accuracy.
// Example: Vision API call
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{
role: 'user',
content: [
{ type: 'text', text: 'Describe this image in 8-12 words for alt text.' },
{ type: 'image_url', image_url: { url: imageUrl } }
]
}],
max_tokens: 60
});
Always human-review — models can hallucinate details, miss context, and don't know your brand/product names. AI is a draft, not a final answer.