What is your hamburger button called?
Enter your domain. We read the HTML your server sends and work out what every button, icon control and role="button" on the page is announced as — the ones with nothing to announce them, the ones whose label contradicts the words on screen, the ones no keyboard can reach — each under the criterion it actually sits beneath.
Free, instant, no signup and no card. Nothing is stored.
Free, instant, no signup and no card. We read the HTML your server sends for that one page and work out what each control is announced as. Nothing is stored.
A button is the one control with no fallback
When a link has no text, a screen reader reads out its URL. It is a miserable experience — slashes and hyphens announced one character at a time — but it is information, and a determined person can get somewhere with it.
A button has no URL. When a button has no name, what is announced is the single word “button”, and that is the entire contents of the message. There is nothing to infer from, nothing to preview, no way to find out what it does short of pressing it and watching what happens to the page. On a page where one of those unnamed controls is “delete account” and another is “close”, that is not a small ask.
And it is invisible. Every unnamed control on a real website looks completely right on screen, because the thing naming it for a sighted reader is a picture — a hamburger, a magnifier, an X, a chevron, a bin. The markup renders perfectly. The defect only exists in the layer nobody on the team looks at.
What this checker refuses to call a failure
A free checker that a stranger runs on their own site has exactly one way to be useless, and it is to cry wolf. So three things are called failures here, each level A, each naming its criterion, and each one a control a real person genuinely cannot announce or operate: a control with no accessible name at all, an image button whose image carries no alt text, and a visible label the accessible name does not contain.
An <input type="submit"> with no value is not unnamed. Every browser supplies “Submit” as the implicit name, and the same for a reset input. The control is named; it is just not named by you. This is the most common false positive in the category and it is worth knowing which tools produce it. The one that genuinely has nothing is <input type="button"> with no value — no browser defaults that — and it is counted.
“Submit” is not a violation. SC 4.1.2 asks a control to have a name, not a descriptive one. A placeholder name is a verify item with the argument attached, not a number in a violation count.
A repeated name is not a violation either. Twelve “Add to cart” buttons in a product grid are conforming markup, and the row each one sits in disambiguates it for a sighted reader. It is reported because the list of controls a screen reader builds has no rows in it — not because WCAG forbids it.
What the checker looks for
Three failures, then the review and verify items — real problems that WCAG does not forbid at level A or AA, or that cannot be proved from served markup, reported separately and never counted as violations.
- Button with no accessible nameFailureSC 4.1.2 Name, Role, Value (Level A)
- There is nothing inside this control and nothing labelling it, so a screen reader announces it as the bare word "button" and stops. A link at least has a URL to fall back on; a button has nothing, so the only way to find out what it does is to press it and see what happens. Almost every one of these is an icon-only control — a hamburger, a magnifier, a cart, a carousel arrow, a close X — which looks entirely correct on screen, which is why it survives every design review the page ever gets.
- The fix: Put words on it. `aria-label="Open menu"` on the button, or alt text on the image inside it, or a visually-hidden span next to the icon. Name the action, not the picture: "Search", not "magnifying glass".
- Image button with no alt textFailureSC 1.1.1 Non-text Content (Level A)
- This control is an image and the image carries no alt attribute, so there is no text anywhere for it to be announced by. On an `<input type="image">` some screen readers fall back to reading the filename out, character by character, which is worse than silence because it sounds like information.
- The fix: Give the image an alt attribute describing what pressing it does — `<input type="image" src="/go.png" alt="Search">`. An empty `alt=""` is not the fix here: on a control it removes the only name it had.
- Visible label missing from the accessible nameFailureSC 2.5.3 Label in Name (Level A)
- This control shows one set of words on screen and hands software a different set. Someone driving the browser by speech says the words they can see — "click Get started" — and the browser matches what they said against the accessible name. When the name does not contain the visible words the match fails, nothing happens, and they are given no reason why.
- The fix: Extend the visible text instead of replacing it. Visible "Save", `aria-label="Save draft"` passes; visible "Save", `aria-label="Persist changes"` does not. If the aria-label is only there to add context, put the visible words at the start of it.
- role="button" on an element that cannot be focusedReviewSC 2.1.1 Keyboard (Level A)
- A div or a span carrying role="button" tells assistive technology that this is a button, but the role does not make the element focusable and does not bring the Enter and Space handling a real `<button>` has for free. In the HTML your server sent there is no tabindex on it, so as delivered it cannot be reached by keyboard at all. This is in the review band rather than the failure count for one honest reason: a framework can add tabindex after hydration, and this reader runs before any script does.
- The fix: Use a real `<button type="button">`. It is focusable, it fires on Enter and Space, it announces its own role, and it costs nothing — role="button" plus tabindex plus two key handlers is the long way round to the same control.
- Clickable element that is not a buttonReviewSC 4.1.2 Name, Role, Value (Level A)
- This element has a click handler on it and no button role, so as far as the browser's accessibility tree is concerned it is a paragraph or a container that happens to react to a mouse. It takes no keyboard focus, appears in no list of controls, announces no role, and cannot be operated by anyone not using a pointer. Only inline handlers are visible to this reader, so what you see here is the floor, not the count — handlers attached in JavaScript are invisible to it and to every other static checker.
- The fix: Make it a `<button type="button">` and let the platform supply the role, the focus and the key handling. Where the markup cannot change, role="button" plus tabindex="0" plus Enter and Space handlers is the manual reconstruction of the same thing.
- Focusable control hidden from assistive technologyReview
- This control carries aria-hidden="true" but is still in the tab order, which produces the worst of both: a keyboard user tabs onto something a screen reader refuses to describe, so focus lands on nothing announced at all and there is no way to tell what has been reached. It is usually a leftover from a modal or an off-canvas menu that hides its contents on one axis and forgets the other.
- The fix: If the control is genuinely inactive, take it out of the tab order too — `tabindex="-1"`, `disabled`, `hidden`, or `display: none` on the container. If it is active, remove the aria-hidden.
- Name comes only from the title attributeVerifySC 4.1.2 Name, Role, Value (Level A)
- The only thing naming this control is its title attribute. That is the last resort in the accessible name calculation and it does work in most screen readers, but a title is not shown on touch, is not shown to keyboard users until a mouse hovers it, and several browsers have shipped periods of not exposing it at all. A name that depends on hovering is not a name a phone user ever gets.
- The fix: Move the words into an aria-label, or into a visually-hidden span inside the control. Keep the title as well if you want the tooltip; just do not let it be the only copy of the name.
- Name says what it is, not what it doesVerify
- The name is a placeholder word — "Submit", "OK", "Go", "Button". This is NOT a WCAG failure and a checker that counts it as one is inflating its number: SC 4.1.2 asks the control to have a name, not a descriptive one, and SC 2.4.6 Headings and Labels at AA is satisfied by a label that describes its purpose, which one "Submit" on one form does. It matters when there are several, because a screen reader's list of controls shows the names with no form, card or column around them to say which is which.
- The fix: Say what the press does: "Create account", "Apply filters", "Delete invoice 1042". Where the visible word has to stay short, extend it in an aria-label rather than replace it, so SC 2.5.3 still holds.
- One name on several controlsVerify
- Several controls on this page announce themselves identically. In the page, the row, the card or the product name next to each one tells you which is which; in the list of controls a screen reader builds, none of that is there — just the same words repeated, with no way to tell the third from the ninth. This is reported as something to look at and never as a violation: SC 4.1.2 asks for a name, not a unique one.
- The fix: Put the distinguishing words in the name and leave the screen alone. Visible "Add to cart", `aria-label="Add Blue Runner, size 9, to cart"` keeps the grid and fixes the list.
- Name is a paragraphVerify
- This control's accessible name runs past 100 characters, which usually means an element was wrapped around a whole card or panel and every word inside it became part of the name. All of it is read out, in full, every time the control is reached, and again every time it appears in a list of controls.
- The fix: Wrap the words that name the action, not the container. Make the surrounding area clickable with a CSS overlay instead of by putting a button around it.
How to name a button, in four rules
Every fix below is one attribute or a copy change, and all of them are cheaper to do than to audit.
- Every icon-only control gets words.
aria-labelon the button, or alt text on the image inside it, or a visually-hidden span next to the glyph. Name the action, not the picture:aria-label="Search", notaria-label="magnifying glass". - Where a button has visible words, extend them — never replace them. Visible “Save”,
aria-label="Save draft and continue"keeps the visible words inside the name, so voice control still works and SC 2.5.3 is satisfied. Replacing them is the failure this page reports. - Use a real
<button>. It is focusable, it fires on Enter and Space, it announces its own role, and it is free.role="button"plustabindex="0"plus two key handlers is the long way round to the same control, and the version that breaks when someone edits the component next year. - In a repeating grid, put the item in the name. Visible “Add to cart”,
aria-label="Add Blue Runner, size 9, to cart". The layout does not change and the list of controls becomes readable.
Common questions
- What does "button has no accessible name" actually mean?
- It means the control arrives at a screen reader with no text attached to it, so all the user is told is the word "button". A link at least has a URL the software can read out as a last resort; a button has nothing behind it, so there is no fallback and no way to find out what it does other than pressing it and seeing what happens. That is the whole failure, and it is SC 4.1.2 Name, Role, Value at level A — the role is there, the name is missing.
- Which buttons is this usually?
- Icon-only ones, almost every time. The hamburger that opens the mobile menu, the magnifier that opens search, the basket in the header, the left and right arrows on a carousel, the close X on a cookie banner or a modal, the play triangle on a video, the bin on a basket row, the three dots on a card. All of them are an SVG or an image inside a <button> with no words anywhere, all of them look completely correct on screen, and that is exactly why they survive every design review the page ever gets. If your site has one of these patterns and no aria-label convention, the checker will find it.
- Does an <input type="submit"> with no value count as unnamed?
- No, and a checker that says it does is wrong. Every browser supplies an implicit name for a submit input — "Submit" — and the same for a reset input. The control is named; it just is not named by you. This tool reports it as a name worth improving rather than a failure, and it is the single most common false positive in this category. The one that genuinely has nothing is <input type="button"> with no value, because no browser supplies a default for that, and that one is counted.
- My icon buttons all have aria-labels. Will they be reported?
- No. An aria-label, an aria-labelledby pointing at real text elsewhere on the page, alt text on the image inside the button, an svg <title>, a visually-hidden span, or an input's value attribute all count as names, because all of them are announced. That is deliberate: the expensive error for a tool a stranger runs on their own site is telling them their correctly-labelled controls are broken. The one thing to watch is the opposite case — an aria-label on a button that also has visible words, where the label does not contain those words. That one IS a level A failure, under SC 2.5.3 Label in Name, and it is reported as one.
- Why is an aria-label that replaces the visible text a failure?
- Because of voice control. Someone driving the browser by speech says the words they can see — "click Save" — and the browser matches what they said against the button's accessible name. If the name is "Persist changes" and the visible word is "Save", the match fails and nothing happens, with no indication why. SC 2.5.3 at level A is the criterion: where a component has a visible text label, the accessible name has to contain that text. Extending is fine and often good: visible "Save", aria-label "Save draft and continue" passes. Replacing is the failure.
- Is a div with role="button" broken?
- Usually, but not in a way this page will call a failure. The role tells assistive technology it is a button; it does not make the element focusable and it does not bring the Enter and Space handling a real <button> gets for free. So a div[role=button] with no tabindex cannot be reached by keyboard as delivered. The reason it is in the review band rather than the failure count is honest and specific: this reader runs over the HTML your server sent, before any JavaScript, and plenty of frameworks add the tabindex during hydration. We will not fail you for something we cannot see the other half of. The advice is unchanged — use a real <button type="button"> and the platform gives you focus, keys and role for nothing.
- Is "Submit" a WCAG violation?
- No. SC 4.1.2 asks the control to have a name, not a descriptive one, and SC 2.4.6 Headings and Labels at AA is satisfied by a label that describes its purpose — which one "Submit" button on one form does. So it sits in the verify band here with the argument attached, not in a violation count. It becomes a real problem in one specific place: the list of controls a screen reader can pull up, which shows the names with no form, card or column around them. Five buttons called "Submit" in that list are five identical rows.
- What does the checker actually read?
- One URL, once. It fetches the page you enter, takes the HTML your server returns, and walks every <button>, every <input> typed submit, button, reset or image, and every element carrying role="button", in document order. For each one it works out the accessible name the way a browser does — aria-labelledby first, then aria-label, then the control's own content including image alt text and svg titles, then the value attribute, then title as a last resort — and asks whether that name exists, whether it contradicts the visible text, and whether the control can be reached at all. It does not render the page, run your JavaScript or crawl beyond the address you typed; all three of those are the full scan, which is a different tool on this site and also free.
- It found no buttons, but my page obviously has some.
- Two possibilities, and both are worth knowing. The first is client-side rendering: if the controls are built by React, Vue or a widget after the document arrives, they are not in the HTML your server sent and this reader cannot see them — the same limitation as the heading, link text, form label and alt text checkers on this site, and the same honest answer. The free scan renders each page in a real browser first, so it sees what your visitors see. The second is worse: the "buttons" may be divs with click handlers attached in JavaScript. Those take no keyboard focus, announce no role, appear in no list of controls, and cannot be operated at all without a pointer. This checker catches the inline-onclick version of that; the scripted version only a rendered scan can see.
- Does this store my domain?
- No. The check is a single HTTP GET of the page you name, run inside the request and discarded when it answers. There is no account, no email field and no row written anywhere. If you go on to run the free scan, that one does keep a report so you can come back to it, which is the whole point of a report.