The accessible name should travel with the graphic
· 8 min read
Alt text lives in the page, so it is left behind the moment the file is reused. A title inside the file goes where the file goes.
Somebody writes alt text once, carefully, for the page they are building. Six months later the same graphic is in a partner site, a slide deck and a quarterly email, and in two of those places it has no name at all.
Nobody was careless. The name was never part of the graphic. It was part of the page, and pages do not travel.
Where a graphic keeps its name
The convention almost everyone learns is that a graphic is named by the markup around it. That is where alt lives:
<img src="/diagram.svg" alt="How a request moves through the pipeline" />
That attribute is doing real work and it is the right place for it. Alt text describes what the graphic means here, on this page, in this argument. The same diagram on a pricing page and in an engineering runbook should not necessarily be described identically, and alt text is how you say so.
The failure is not the attribute. The failure is that it is the only copy of the name. Move the file and the name stays behind, and whether it gets rewritten depends on whether the next person knew it was their job.
The three places it goes wrong
It gets dropped
The most common outcome. A graphic is embedded somewhere the original author never saw, by somebody exporting a deck or pasting into a CMS, and the alt attribute is simply absent. A screen reader announces the filename, or announces nothing.
It gets retyped, differently
Three people describe the same architecture diagram three ways. None of them is wrong. All of them are inconsistent, and a reader who meets the graphic twice hears about two different things.
It gets filled in by a tool
A CMS that requires alt text and a person who needs to publish produces alt="image" or alt="diagram", which is worse than an empty alt: it passes the automated check and tells the reader nothing.
An SVG can name itself
SVG has elements for exactly this. A title is the accessible name; a desc is a longer description. Referenced from the root with aria-labelledby and paired with role="img", they are what assistive technology reads:
<svg role="img" viewBox="0 0 320 200"
xmlns="http://www.w3.org/2000/svg"
aria-labelledby="pipelineTitle pipelineDesc">
<title id="pipelineTitle">How a request moves through the pipeline</title>
<desc id="pipelineDesc">A request enters at the gateway, is queued, processed by a
worker, and written to storage. Failures return to the queue once before alerting.</desc>
<!-- the drawing -->
</svg>
That name is inside the file. Copy the file into a partner site and the name goes with it. Paste it into a deck and it is still there. Nobody has to know it was their job, because it was already done.
Note role="img" specifically. Without it, some assistive technology walks into the SVG and reads the shapes, which is a worse experience than either naming or skipping it. The role tells the reader to treat the whole thing as one image, and the title tells it what that image is.
Use both, and know which one wins
This is not a replacement for alt text and treating it as one is the mistake to avoid. Keep both:
<!-- The page still says what this graphic means HERE. -->
<img src="/diagram.svg" alt="Request flow, referenced in step 3 below" />
<!-- The file still says what it IS, wherever it ends up. -->
<svg role="img" aria-labelledby="t">
<title id="t">How a request moves through the pipeline</title>
...
</svg>
When a graphic is referenced with img, the alt attribute wins and the title inside the file is not announced. That is correct: page context should beat file context, because the page knows why the graphic is there. The title earns its keep in every other situation, which is every situation where nobody wrote an alt attribute at all.
And a genuinely decorative graphic still takes an empty alt so it is skipped rather than announced. A name inside the file does not change that judgment. A divider flourish that introduces itself is noise.
The high-contrast half of the same problem
Naming is one accessibility failure that travels with a graphic. Color is the other. A reader who has turned on a high-contrast mode has told their operating system that they need the palette to be theirs, and a graphic with baked-in fills ignores that.
The same file that carries its own name can answer that too, in the same stylesheet:
@media (forced-colors: active) {
.surface { fill: Canvas; }
.ink { fill: CanvasText; }
.line { stroke: CanvasText; }
}
Canvas and CanvasText are system colors: the browser substitutes whatever the reader has chosen. The graphic stops insisting on its own palette and starts deferring to theirs, which is the entire point of the setting.
What a screen reader does with an unnamed graphic
It helps to know what actually happens, because the failure is not always silence.
An img with no alt attribute at all is often announced by its filename. A reader hears "logo dash dark dash two x dot s v g, image", which is worse than nothing: it is noise that sounds like information. An img with alt="" is skipped entirely, which is correct for decoration and wrong for content.
An inline SVG with no name and no role is the messiest case. Some assistive technology walks into it and encounters the shapes, announcing group after group, or reads any stray text node inside the drawing out of context. A label that reads "4.6 KB" inside an illustration becomes an announcement with no subject.
Adding role="img" is what stops that. It tells the reader to treat the element as a single image and not to descend into it. On its own it produces an unnamed image, which is why the role and the title belong together and neither is much use alone.
Title, desc, aria-label: which one and when
There are several ways to name an SVG and they are not equivalent.
title, referenced with aria-labelledby
The default choice. It lives in the file, travels with it, and is what we generate. Referencing it explicitly from the root is what makes support reliable, because relying on an unreferenced first-child title has historically been inconsistent across readers.
desc, for the detail a name cannot hold
A name should be short. A diagram often needs more than short: a sequence, a set of relationships, the thing a sighted reader gets from following the arrows. That is what desc is for, referenced alongside the title.
<svg role="img" aria-labelledby="flowTitle flowDesc">
<title id="flowTitle">Request flow</title>
<desc id="flowDesc">Four stages left to right: gateway, queue, worker, storage.
A failed job returns to the queue once before it raises an alert.</desc>
</svg>
aria-label, when the file is not yours to edit
An attribute on the root element overrides whatever is inside. It is useful when you are placing a third-party graphic you cannot change, and it has the same weakness as alt text: it lives in the page, so it does not travel.
The empty alt is a decision, not an omission
The most common review comment on accessibility work is that everything needs alt text. It does not, and treating it that way produces worse pages.
A graphic that carries meaning needs a name. A graphic that is there because the layout would look bare without it should be silent, and silence has to be requested explicitly:
<!-- Meaningful: name it. -->
<img src="/architecture.svg" alt="Request flow through the pipeline" />
<!-- Decorative: silence it deliberately. -->
<img src="/flourish.svg" alt="" />
<!-- Decorative and inline: same idea, different attribute. -->
<svg aria-hidden="true" focusable="false"> ... </svg>
The focusable="false" on that last one matters in older engines, where an SVG could otherwise take keyboard focus while being hidden from the accessibility tree. A control that can be focused but not announced is a trap, and it is the kind of defect that only shows up when somebody actually tabs through the page.
A pattern for teams that generate their icons
Most design systems do not hand-author every graphic. They generate a set from a source, and generation is exactly where a naming convention can be enforced instead of hoped for.
If your pipeline already stamps a viewBox and strips editor metadata, it can stamp a name too. The name comes from the same place the filename comes from, so it is never missing and never invented at publish time:
// One place decides how every generated icon is named.
function withAccessibleName(svg, { id, label }) {
const titleId = id + "-title"
return svg
.replace("<svg", `<svg role="img" aria-labelledby="${titleId}"`)
.replace(/(<svg[^>]*>)/, `$1<title id="${titleId}">${escapeXml(label)}</title>`)
}
The interesting part is not the code, it is where the label comes from. If it comes from a field the designer fills in when they add the icon, the description is written by the person who knows what the icon means. If it is derived from the filename, you get "arrow-right" read aloud, which is a machine name rather than a description and tells a reader nothing about what the arrow does.
That difference is worth a column in a spreadsheet. A set of eighty icons needs eighty short descriptions, written once, by somebody who can answer "what would I say if I were reading this page aloud". It is an afternoon of work and it never has to be repeated.
How to test this without guessing
Automated checkers are useful and they are not sufficient. They will tell you an alt attribute is missing. They cannot tell you that alt="image" is useless, or that the name you wrote describes the wrong thing.
- Read the accessibility tree in your browser devtools. Every graphic should appear as an image with a name you would be happy to hear read aloud.
- Tab through the page. Nothing decorative should take focus, and everything focusable should be announced.
- Turn on a screen reader and listen to one page end to end. It is uncomfortable the first time and it is the only way to hear what your pages actually sound like.
- Turn on high contrast at the operating system level and look at every graphic, not just the interface.
- Reuse a graphic somewhere else deliberately, then check whether it still has a name.
That last test is the one this post is really about, and it is the one nobody runs, because the reuse happens six months later in somebody else project.
Where this fits with the design system
Names inside files change who owns the description. Today it is owned by whoever writes the page, which means it is written last, under deadline, by a person who did not draw the graphic.
Moving it into the file moves it to the person who did draw it, at the moment they drew it, when they still know what it is meant to convey. That is a better place for it in the same way that a design token is a better place for a color than a hex value pasted into a stylesheet: closer to the decision, further from the transcription.
What this is not
It is not a compliance guarantee, and we will not sell it as one. Conformance is a property of a whole page and of how people actually use it, not of one file. Automated checks can find a missing name; they cannot tell you whether the name is any good.
What this removes is narrower and worth having on its own: a graphic that reaches a screen reader anonymous, in the places nobody remembered to check.
A short checklist
- Give every meaningful SVG a title, referenced from the root with aria-labelledby, and role="img" so it is read as one image.
- Add a desc when the graphic carries detail a one-line name cannot hold, such as a diagram with a sequence in it.
- Keep writing alt text on the page. It describes meaning in context and it wins where both exist.
- Give decorative graphics an empty alt so they are skipped.
- Answer forced-colors so a reader who needs their own palette gets it.
- Test with the screen readers your audience actually uses, not only with an automated checker.
If you want to see what this looks like on your own files, start on the free account and run one through. Tell us where it falls short; every report goes on our public board.
Related posts
Post Details
· 8 min read