Skip to main content
Accessibility Axe Core 4.11

Frames should be tested with axe-core

About This Accessibility Rule

Why This Matters

Web pages often embed content using iframe or frame elements — for ads, third-party widgets, embedded forms, video players, or even internal application components. Each frame is essentially its own document with its own DOM. If axe-core is not running inside those frames, any accessibility violations within them go completely undetected.

This is classified as a critical user impact issue — not because the frame itself is inaccessible, but because undetected violations inside frames can affect all users with disabilities. Blind users relying on screen readers, sighted keyboard-only users, and deafblind users could all encounter barriers hidden within untested frame content. Missing form labels, broken focus management, insufficient color contrast, or missing alternative text inside frames would remain invisible to your testing process.

This rule is a Deque best practice rather than a specific WCAG success criterion. However, the violations that go undetected inside untested frames can relate to numerous WCAG criteria, including 1.1.1 (Non-text Content), 1.3.1 (Info and Relationships), 2.1.1 (Keyboard), 2.4.3 (Focus Order), 4.1.2 (Name, Role, Value), and many others. Comprehensive accessibility testing requires that all content on a page is analyzed, including content within frames.

How the Rule Works

When the iframes configuration property is set to true, axe-core attempts to run inside every iframe and frame element on the page. The rule uses both frame and iframe selectors to check whether the axe-core script is present in each frame’s document. If axe-core is not found inside a frame, the rule returns a “needs review” result for that element.

The rule operates at the page level — meaning results from nodes across different frames are combined into a single result when the entire page is tested. An optional after function processes results from all frames together.

How to Fix It

There are several approaches to ensure frames are properly tested:

  1. Use axe-core’s built-in iframe support. When running axe-core programmatically, set the iframes option to true (this is the default). axe-core will automatically attempt to communicate with frames to gather results — but the axe-core script must be present in each frame for this to work.

  2. Inject axe-core into all frames. If you control the frame content, include the axe-core script in those documents. If you’re using a testing framework like Selenium, Puppeteer, or Playwright, inject the axe-core script into each frame before running the analysis.

  3. Use axe DevTools browser extension. The axe DevTools extension handles frame injection automatically in most cases, making it the simplest option for manual testing.

  4. For third-party frames you don’t control, acknowledge that testing coverage is limited and consider testing the third-party content separately, or document it as an area requiring manual review.

Examples

Frame that triggers the issue

An iframe is present on the page, but axe-core is not loaded inside it. The content within the frame remains untested:

<main>
  <h1>Our Application</h1>
  <iframe src="https://example.com/embedded-form" title="Contact form"></iframe>
</main>

If https://example.com/embedded-form does not have axe-core loaded, axe will flag this frame as needing review.

Correct setup with axe-core injected

When using a testing tool like Playwright, ensure axe-core is injected into all frames:

const { AxeBuilder } = require('@axe-core/playwright');

// AxeBuilder automatically analyzes iframe content
const results = await new AxeBuilder({ page })
  .analyze();

Frame content that includes axe-core

If you control the frame source, include the axe-core script directly:

<!-- Content inside the iframe document -->

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Embedded Form</title>
  <script src="/vendor/axe-core/axe.min.js"></script>
</head>
<body>
  <form>
    <label for="email">Email address</label>
    <input type="email" id="email" name="email">
    <button type="submit">Subscribe</button>
  </form>
</body>
</html>

Properly structured frame on the parent page

Always ensure your frames have descriptive title attributes so users understand their purpose:

<iframe src="/embedded-form.html" title="Newsletter subscription form"></iframe>

This won’t fix the axe-core injection issue by itself, but it ensures the frame is accessible while you work on getting full test coverage inside it.

Help us improve our guides

Was this guide helpful?

Detect accessibility issues automatically

Rocket Validator scans thousands of pages with Axe Core and the W3C Validator, finding accessibility issues across your entire site.

Ready to validate your sites?
Start your free trial today.