sfw/fix
frame-title high

Frames must have an accessible name

An iframe has no title attribute, so screen readers announce it as just "frame" with no clue what's embedded inside.

What you see

Frames must have an accessible name
<iframe> element has no title attribute
<iframe src="https://www.youtube.com/embed/..."></iframe>

What’s actually happening

axe flags an <iframe> (or legacy <frame>) with no title. A screen reader user tabbing or navigating by frame hears "frame" — or the raw src URL — and has to guess what's in it. On a page with three or four embeds (a video, a map, a payment widget, an ad), they all announce identically, so there's no way to tell the checkout iframe from the YouTube one without entering each and poking around. Sighted users never notice; the frame renders normally.

Common causes

  • An embed snippet pasted from YouTube, Vimeo, Google Maps, or a payment provider shipped without a title and nobody added one
  • A tracking or ad iframe injected by a third-party script has no title and isn't under your direct control in the template
  • A CMS block or page builder outputs <iframe> from a URL field but offers no place to set a title
  • Multiple iframes on the page each have a title, but they're identical ("Embedded content"), so they fail to distinguish themselves
  • An old frameset still in use has <frame> elements with no title and no name attribute

How to fix it

  1. Add a concise, specific title to every iframetitle="..." is the accessible name for a frame. Describe the content, not the mechanism: title="Office location map", title="Product demo video", title="Stripe card payment form". One short phrase. The browser exposes it directly to AT — no ARIA needed.
  2. Make titles unique when a page has several framesTwo iframes both titled "Video" still leave a screen reader user unable to pick one. Differentiate them: "Installation walkthrough video", "Customer testimonial video". The title's job is to let someone choose the right frame from a list, so it has to be distinguishable.
  3. Hide purely decorative or empty iframes from ATSome injected iframes (tracking pixels, an ad slot rendered as 0×0) carry no user-facing content. If the frame genuinely has nothing to offer, add title="" together with aria-hidden... no — for frames specifically, give it an empty-but-present title only if it's truly presentational; better, if you control it, set tabindex="-1" and a title like "Advertisement" so it's at least identifiable rather than silent.
  4. Handle third-party embeds at the wrapper you controlWhen a script injects the iframe and you can't edit its attributes, set the title in the embed config if the provider exposes one (YouTube's iframe API, Google Maps embed options). Failing that, intercept after load — querySelector the iframe and set .title in the same script that mounts it.
  5. Re-scan and confirm the announced nameRun axe again; the frame-title item should clear. Then in VoiceOver press VO+U or navigate by frame and check each one announces its real title instead of "frame" or a URL.

Stop it recurring

Add a title attribute to every iframe in your embed components and templates, and lint for <iframe> without title so a bare embed fails the build.

Related errors