Is your embed announced as just “frame”?
Your map, your YouTube player, your Calendly booker and your Stripe card field are each a separate document that takes keyboard focus. If they have no title, a screen reader announces them as the word “frame” — or reads the embed URL out loud. Enter any page and we show you its frames list, in order, in the words it is actually announced with.
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. Nothing is stored.
The list nobody who built the page has ever seen
JAWS and NVDA both expose a frames list, the way they expose a links list and a headings list. No browser shows it to you. It is not in the rendered page, it is not in a screenshot, and it does not appear in any review a normal team runs — so it is one of the few parts of a site that ships unlooked-at by definition, not because anyone was careless but because there was nowhere to look.
Here is what it reads on four sites, read live on 23 September 2026:
web.dev frame
→ Google's own web-quality site, one unnamed embed
developers.google.com/search
frame
→ the profile widget, also unnamed
kubernetes.io frame
→ an <iframe srcdoc> with nothing to announce
w3schools.com/html/… W3Schools HTML Tutorial, frame
→ named. This is all it takes.
nasa.gov (empty — 2 frames, both correctly hidden)
→ display:none is out of the tab order tooThree of those four sites are run by organisations with accessibility teams, and the one that gets it right is a tutorial site demonstrating the tag. That is what a defect looks like when it lives in an artefact nobody is shown.
What WCAG actually says about frames
More than it says about most things a checker will scold you for. An <iframe> is a user interface component — it takes keyboard focus and it contains more components that do — so SC 4.1.2 Name, Role, Value at Level A applies, and WCAG’s own sufficient technique for it is H64: use the title attribute of the frame element. An unnamed frame is a Level A failure, this tool says so, and it is one of the few findings in accessibility that needs no qualification.
Everything else on the list is reported for a look, with the criterion named where one genuinely applies and left off where it does not. A frame set to scrolling="no" is a plausible SC 1.4.10 Reflow problem at 400% zoom and is reported as one to check — not as a failure, because whether anything overflows depends on a document on another origin that nothing here is allowed to read.
That restraint is the tool. Telling a stranger their working site “fails WCAG” because their tag manager ships a hidden frame is how accessibility scanners lose the room.
What this checker refuses to call a failure
Frames are unusual: the correct shapes are more common than the defects, because every site on the internet carries a hidden analytics frame. So the negatives are pinned as hard as the positives, by scripts/check-iframe-audit.mjs in the build:
<!-- correct — one attribute, and it is the whole fix -->
<iframe src="https://maps.google.com/…" title="Map of our Denver office">
<!-- correct — hidden from everybody, never reported -->
<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-X"
height="0" width="0" style="display:none;visibility:hidden">
<!-- correct — the documented way to drop a decorative frame -->
<iframe src="/deco" aria-hidden="true" tabindex="-1">
<!-- correct — a resolving reference is a name -->
<h2 id="map-heading">Where to find us</h2>
<iframe src="…" aria-labelledby="map-heading"><!-- fails 4.1.2 — announced "frame", or as its own URL --> <iframe src="https://calendly.com/acme/30min"> <!-- fails 4.1.2 — present, empty, and reads as titled in every review --> <iframe src="…" title=""> <!-- fails 4.1.2 — out of the a11y tree, still reachable by Tab --> <iframe src="…" aria-hidden="true"> <!-- the common tidy-up — YouTube's own copy-paste default, three times --> <iframe title="YouTube video player"> × 3
A frame hidden with display:none, visibility:hidden or the hidden attribute is out of the accessibility tree and out of the tab order at the same time, which is correct and complete — it is never counted, never reported and never called untitled. Every site has one or two, which is what makes that the loudest false positive available here.
And the honest gap: we read the HTML your server sends and do not run your JavaScript. A page whose markup has no frames and almost no content is reported as verify — a client-rendered shell — rather than as a page with no embeds, because a cookie banner deferring every player until consent is the ordinary case, not the exception.
A frame has no name at all
FailsWCAG 2.1 SC 4.1.2 Name, Role, Value (Level A)
An <iframe> on this page carries no title, no aria-label and no aria-labelledby, and it is not hidden. A screen reader announces it as "frame" — or reads out the embed URL, which on a modern map or payment widget is two hundred characters of query string. The reader is told there is a destination here and nothing about what is in it, and because an iframe takes focus they can tab straight inside it and keep going.
A frame's name is there and blank
FailsWCAG 2.1 SC 4.1.2 Name, Role, Value (Level A)
An <iframe> carries title="" or aria-label="" — the attribute is present and its value is empty or whitespace. This is worse than nothing, because every code review and most linters see a titled frame. An empty string is not a name: the frame announces exactly as an untitled one does. It is usually a template variable that resolved to nothing.
A frame is hidden from screen readers and still in the tab order
FailsWCAG 2.1 SC 4.1.2 Name, Role, Value (Level A)
A frame carries aria-hidden="true" but is still displayed and still focusable — it has no tabindex="-1". An iframe is focusable by default, so this is the contradiction that breaks a keyboard user hardest: everything inside the frame stays reachable by Tab while being deleted from the accessibility tree. A screen reader user tabs forward and focus lands somewhere the screen reader has nothing to say about, and they cannot tell whether the page moved or their software failed.
A frame's label points at something that isn't there
FailsWCAG 2.1 SC 4.1.2 Name, Role, Value (Level A)
A frame carries aria-labelledby with an id that does not exist anywhere in this page's HTML. ARIA does not fall back when a reference is broken — it does not use the title attribute, it does not warn, it simply drops the name. The frame announces as an unnamed one while the markup looks labelled in every review it will ever get.
Two frames announce as exactly the same thing
ReviewWCAG 2.1 SC 4.1.2 Name, Role, Value (Level A)
Two or more frames on this page share an accessible name, so the frames list has entries that cannot be told apart — most often three copies of "YouTube video player", the default title the embed code ships with. The list is a shortcut, and a shortcut with identical entries makes the reader open each one to find out which is which.
A frame is named after being a frame
ReviewWCAG 2.1 SC 4.1.2 Name, Role, Value (Level A)
A frame's name is a word that describes the container rather than the content — "iframe", "frame", "embed", "embedded content", "widget", "content", or a vendor default like "YouTube video player". The role is announced anyway, so the reader hears the same word twice and learns nothing. It is not a conformance failure on its own; it is a name that spent itself saying what the browser was going to say for free.
A frame is named with its own URL
ReviewA frame's title is the embed URL, or starts with https://. Screen readers read a URL out character group by character group, so a fifty-character embed link becomes several seconds of announcement that tells the reader nothing they wanted — and a widget URL with tracking parameters can run far longer than that. This is what an unnamed frame falls back to anyway, so the attribute is doing no work.
A frame carries role="presentation"
ReviewWCAG 2.1 SC 4.1.2 Name, Role, Value (Level A)
A frame carries role="presentation" or role="none" while still being focusable. ARIA specifies that the presentation role is ignored on a focusable element — the browser puts the real role back — so this attribute does not do what it looks like it does, and a name that was omitted because "the role removes it" was omitted for nothing.
A zero-size frame is still in the page
ReviewA frame is sized to zero — width="0", height="0" or a style that collapses it — but is not hidden with display:none, visibility:hidden or the hidden attribute. These are almost always trackers, and collapsed is not hidden: the frame stays in the accessibility tree and stays focusable, so it appears in the frames list as an empty destination and can take a Tab press to nowhere. The fully hidden ones are ignored by this checker on purpose, because every site has them and they are fine.
A frame is set to scrolling="no"
ReviewWCAG 2.1 SC 1.4.10 Reflow (Level AA)
A frame carries scrolling="no" or a CSS overflow:hidden, which clips whatever does not fit instead of letting the reader reach it. At 200% or 400% zoom an embedded form or map is taller than the box the page gave it, and the part below the cut is now unreachable by any means. This is reported for a look rather than called a failure, because whether anything actually overflows depends on a document on another origin that we are not allowed to read.
We cannot see this page's frames
VerifyThe HTML your server sent contains no frames and almost no content — it looks like a client-rendered shell that mounts its real markup after JavaScript runs. Embeds are also the single most commonly deferred thing on the web: a cookie banner holds the YouTube player back until consent, and a lazy-loader holds the map back until you scroll. So an empty result here is not a result.
The fix, in full
One attribute per embed, and one decision about the decorative ones. There is no library, no wrapper and no ARIA pattern to learn.
<!-- the video: name the video, not the player -->
<iframe src="https://www.youtube.com/embed/…"
title="Product tour, 3 minutes"></iframe>
<!-- the map: name the place -->
<iframe src="https://maps.google.com/…"
title="Map of our Denver office"></iframe>
<!-- the booker: name the action -->
<iframe src="https://calendly.com/acme/30min"
title="Book a 30-minute call"></iframe>
<!-- the tracker: hide it from everybody, not just from one of them -->
<iframe src="https://…/pixel" style="display:none"></iframe>Name what the embed is, the way you would describe it to somebody on the phone. “Map” is not a name — the role is announced anyway, so it reads as “map, frame” and the reader has learned nothing. “Map of our Denver office” costs four more words and ends the question.
Then do a search for YouTube video player across the codebase. That string is in the copy-paste embed snippet YouTube gives you, which is why it is the most duplicated frame name on the web and why three videos on one page so often produce three identical entries.
The one thing you cannot fix from here is what is inside the frame — a different document on a different origin, with its own contrast, its own labels and its own keyboard behaviour. Ask the vendor for their conformance report in writing; a VPAT is the document to ask for by name.
Common questions
- What does an untitled iframe actually sound like?
- Either the single word "frame", or the embed URL read out loud. Modern embeds carry long query strings — a Calendly booker or a payment field can be two hundred characters — and a screen reader will read that URL in character groups, for several seconds, before the reader learns nothing from it. That is the whole defect, and title="Booking calendar" is the whole fix.
- Is a missing iframe title really a WCAG failure?
- Yes, and unusually clearly for something this small. An <iframe> is a user interface component that takes keyboard focus, so SC 4.1.2 Name, Role, Value at Level A applies to it, and WCAG lists technique H64 — using the title attribute of the frame element — as the sufficient technique. This is one of the few things a checker can call a Level A failure without stretching, which is why this tool does and says so plainly.
- Do I need aria-label as well, or a wrapper, or a role?
- No. One title attribute on the iframe is complete. aria-label works too and wins over title if you use both, and aria-labelledby pointing at the heading above the embed works as well. There is no combination you have to ship — pick one, and never ship two that disagree.
- Why is my Google Tag Manager frame not reported?
- Because it is hidden from everybody, which is correct. A frame with display:none, visibility:hidden or the hidden attribute is out of the accessibility tree AND out of the tab order, so it is not in the frames list and it cannot be tabbed into. The tag manager noscript snippet ships exactly that way. Every site on the internet has one or two of these; reporting them would bury the frames that matter.
- What about aria-hidden="true" on a decorative embed?
- On its own it is a failure, and the worst one on this list — an iframe is focusable by default, so aria-hidden without tabindex="-1" leaves the frame and everything inside it reachable by Tab while deleting it from the accessibility tree. A reader tabs forward and focus goes somewhere their screen reader has nothing to say about. The correct pair is aria-hidden="true" together with tabindex="-1", and that combination is silent here.
- Three of my videos say "YouTube video player". Is that a fail?
- Not a conformance failure — they have names. It is reported for a look, because the frames list is a shortcut and three identical entries make the reader open each one to find out which is which. The string comes from YouTube's own copy-paste embed code, which is why it is the most duplicated frame name on the web. Replace it with the video: "Customer story: Northwind", "Product tour, 3 minutes".
- Can you check inside the frame?
- No, and nothing here pretends otherwise. The embedded document is on another origin and a browser will not let any script read it — that is the same-origin policy, not a limitation of this tool. So your booking widget's own contrast, its own labels and its own keyboard traps are its vendor's responsibility, and worth asking them about in writing. What is yours is the name on the frame.
- Why did you say my page has no frames when it clearly has a video?
- Almost always because the embed is deferred. A cookie banner holds YouTube back until consent, and a lazy-loader holds a map back until you scroll — embeds are the single most commonly deferred thing on the web. This reads the HTML your server sends, deliberately: it is fast, free, and the same markup a crawler sees. When that HTML has no frames and almost no content the result is reported as verify rather than as a clean pass. The free WCAG 2.1 AA scan renders each page in a real browser and sees what mounts.
- Does this store my domain?
- No. The check is an 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.
Keep reading
- Do your videos have captions? →
- Can a keyboard reach everything a mouse can? →
- What does your region list say? →
- Is your ARIA being thrown away? →
- What starts before anyone clicks? →
- What is your hamburger button called? →
- Did your CSS delete the focus ring? →
- The VPAT your vendor should have →
- Are your PDFs readable? →
- The WCAG compliance tool →