Keyboard and focus Rule

Frames with controls inside must not have tabindex=-1 frame-focusable-content

An iframe with tabindex="-1" is taken out of the Tab order, and so is everything inside it. If the frame holds a booking form, a map, a video player or a payment field, keyboard users cannot reach any of it. Remove the tabindex. If the frame is not meant to be used by anyone, hide it properly instead.

WCAG 2.2 A 2.1.1 Keyboard

Websight reports this as Frames with focusable content must not have tabindex=-1

Who it affects

Someone booking a dentist appointment with the keyboard Tabs down the page, reaches the embedded booking form, and focus jumps over it to the footer. The form is right there on screen and they cannot type into it.

Someone using a screen reader may be able to read the text in the frame but cannot press its buttons, because focus never enters it.

The developer who added the attribute to stop a focus ring appearing round the frame cannot see the problem with a mouse and does not hear about it until a patient phones the surgery to book.

Broken versus fixed

The broken markup is shown as code rather than rendered, because the effect is in how it is announced or handled, not how it looks.

Broken
<h2>Book an appointment</h2>
<iframe src="https://booking.example/mill-street-dental" title="Book an appointment" tabindex="-1"></iframe>
<p><a href="/contact">Or phone the surgery</a></p>

Tab from the heading goes straight to the phone link. The booking form inside the frame is unreachable from the keyboard.

Fixed
<h2>Book an appointment</h2>
<iframe src="https://booking.example/mill-street-dental" title="Book an appointment"></iframe>
<p><a href="/contact">Or phone the surgery</a></p>

Tab enters the frame, moves through the form fields inside it, then comes out the other side to the phone link.

Test it by hand in two minutes

  1. Click just above the frame and press Tab. Focus should move into the frame's first control, with a visible outline.
  2. Right click the frame, choose Inspect, and look for tabindex="-1" on the iframe element.
  3. Keep pressing Tab inside the frame. Focus should pass through its controls and leave again; it should not skip them and it should not get stuck.
  4. If the frame is display only (a map tile, an advert), check there are no buttons or links inside it. If there are, they are the problem.

The fix

Before
<iframe src="https://booking.example/mill-street-dental" title="Book an appointment" tabindex="-1"></iframe>
After
<iframe src="https://booking.example/mill-street-dental" title="Book an appointment"></iframe>

There is almost never a reason to put tabindex on an iframe. Delete it and let the browser handle focus.

Frame that nobody should use

Before
<iframe src="/pixel.html" tabindex="-1"></iframe>
After
<iframe src="/pixel.html" title="Tracking pixel" hidden></iframe>

If the frame has no content a person should use, hide it from everyone with the hidden attribute rather than only from the Tab key.

Focus ring on the frame itself

Before
<iframe src="/map.html" title="Map" tabindex="-1"></iframe>
After
<iframe src="/map.html" title="Map" class="map-frame"></iframe>
<style>.map-frame:focus { outline: none; } .map-frame:focus-visible { outline: 2px solid #1d4ed8; }</style>

If the frame was given tabindex="-1" to tidy up a focus ring, style the ring instead. Keep it visible for keyboard users.

Common mistakes

  • Using tabindex="-1" to stop a focus outline appearing round the frame; style the outline instead.
  • Planning to focus the frame from script after adding tabindex="-1": that focuses the frame element, not the controls inside it.
  • Adding tabindex="0" to the frame as well, which only adds an empty extra Tab stop.
  • Hiding a frame with opacity or by moving it off screen while it still holds a form.

WCAG criteria this rule maps to

axe-core tags this rule as WCAG 2.2 level A. It is one of the checks for:

The scanner looks for frame and iframe elements with tabindex="-1" and checks whether the document inside has focusable elements. It can only look inside frames from the same site; for a frame from another domain it cannot see the content and asks for a person to check. Automated tools find only part of the accessibility problems on a page; a pass on this rule is not a pass on the criterion.

Scan your own page for this and 63 other checks

Open any page in Chrome, click Websight, and get a score out of 100 with every issue explained and a draft fix snippet per element.

Add Websight to Chrome

Free scans, no account, nothing leaves your computer. Automated tools find only part of the problems; the extension says so on every report.