Analyzing iframes
How the Axe DevTools for Web CLI analyzes content inside iframes, and how to reach elements inside a frame.
Pages often put substantial content inside <iframe> elements: payment forms, media players, embedded maps, chat and help widgets, and third-party components. The CLI analyzes the content of those frames as part of an ordinary page analysis, so framed content isn't a gap in your coverage.
There is nothing to turn on. axe-core is loaded into the frames of the page, each frame is analyzed along with the top-level document, and the results are combined into the same JSON result file for the page.
How Frame Results Are Reported
Results from frames arrive in the same violations, passes, incomplete, and inapplicable arrays as the rest of the page. What identifies them is the target array on each result node: it holds one selector per level of frame nesting, followed by a selector for the element itself.
- A
targetwith one entry is an element in the top-level document. - A
targetwith two entries is an element inside one frame: the first selector finds the frame in the parent document, and the second finds the element inside that frame's document. - Each additional entry represents another level of frame nesting.
This means a report can point at an element that doesn't exist in the page's own HTML. Read the target array from the outside in to find where the element actually lives.
Targeting Elements Inside a Frame
To act on or analyze an element inside a frame, use a spec file and give the selector as a list. All selectors in the list except the last identify successive <iframe> elements to navigate into, and the last identifies the target element inside the innermost frame. See Selectors for the full rules and examples.
# Analyze only the card form inside the card-fields frame,
# which is itself inside the payment-widget frame
analyze only element ["iframe.payment-widget", "#card-fields", "form"]
# Analyze the page, but skip everything inside a third-party frame
analyze the page excluding element [".third-party-frame", "html"]Write the list with no space between [ and the first quotation mark, or the spec file fails validation.
Frame-aware selectors work for page actions as well as for analyze, so a workflow can click a button or fill a field inside a frame before analyzing the result. See Page actions.
Because a list of selectors is always read as a path through frames, it can't be used to select several unrelated elements. To scope an analysis to more than one region of a page, repeat the element clause.
Frames and URI Mode
The --include and --exclude options of axe <url> take a comma-separated list of CSS selectors that are evaluated against the top-level document only, so they cannot target an element inside a frame. Content inside frames is still analyzed; you just can't scope to it from the command line.
Two consequences are worth knowing:
- Naming a frame element, as in
--include "#checkout-frame", scopes the analysis to that frame and everything inside it, because the frame's content is analyzed with it. - Extra selectors after the first are silently ignored when they don't match anything in the top-level document.
--include "#outer,#inner,#leaf"produces exactly the same results as--include "#outer", with no warning that the rest of the path was dropped. A selector that exists only inside a frame fails outright withNo elements found for include in page Context.
Use a spec file when you need to target something inside a frame.
The axe-core frame-tested rule reports any frame that axe-core could not reach, which is how you tell "no issues in this frame" apart from "this frame was never analyzed." It is a best-practice rule, so it is not part of the WCAG rulesets the CLI runs by default; to get those results, use a custom ruleset that includes best-practice rules. See Custom Rulesets.
