v151 · Web APIs · Permissions Policy
Permissions Policy: focus-without-user-activation
Chrome 151 introduces the focus-without-user-activation Permissions Policy directive, giving top-level pages control over whether embedded iframes can programmatically steal focus without a prior user gesture.
background
Browsers already block pop-up windows without user activation, but iframes embedded in a page could call element.focus() at any time — including when the user is actively typing in a different field. This allowed ad iframes, trackers, and malicious embeds to disrupt user interaction by redirecting keyboard focus unexpectedly.
The focus-without-user-activation Permissions Policy directive lets a page deny this capability to its iframes. When denied, any focus() call from the iframe that occurs without a preceding user activation (click, keypress, etc.) is silently ignored.
concepts
-
Focus Demo
Two iframes — one with
focus-without-user-activationallowed, one denied — both trying to callfocus()on a button automatically. Shows which succeeds. -
Policy Reference
Default allowlist, iframe sandbox interaction, and recommended header patterns for embedding third-party content safely.
-
Typing Interrupt
A real iframe fires
element.focus()every 3 seconds — the classic focus-stealing pattern. Toggle between allow and deny and type in the form field to see whether the widget can steal your keyboard focus. A live event log counts attempted, stolen, and blocked focus calls. -
Focus-Steal Attack Replay
Three real-world attack patterns reproduced with iframes — credential overlay, polled-poll embed, sandwich attack with two competing embeds. Replay them with the policy off, then enable it and watch the attempts get blocked. Includes a live event log and counters.
-
Header Codegen
Pick a deployment preset (default, news, bank/SaaS, CMS), choose whether self / cross-origin / named origins are allowed, and emit the right HTTP header, the
<meta>equivalent, and the per-iframeallow=""attribute. Plus a lint that flags risky combinations. -
Capability fallback explorer
Choose an embed policy, replay load-time versus user-activated focus attempts, and generate the matching
Permissions-Policyheader or iframe fallback for production embeds. -
Production Recipe
Three real deployment scenarios — chat embed, media player, and widget host — each with the recommended HTTP header, iframe
allowattribute, a live policy probe usingdocument.featurePolicy, and a focus-without-gesture test that shows whether the policy is actually enforced in your browser. -
Failure Mode Lab
10 failure-mode and edge-case tests: API detection, policy default state, focus() with no user gesture, focus() after user gesture, iframe policy inheritance,
document.featurePolicyAPI, policy header parsing fallback, secure context, cross-origin iframe denial, and recovery patterns. All run without navigation or iframes.
the change
<!-- Allow the iframe to focus elements without user activation (default behaviour) -->
<iframe src="https://embed.example/"
allow="focus-without-user-activation"></iframe>
<!-- Deny focus stealing: iframe's focus() calls need user activation -->
<iframe src="https://ad.example/"
allow="focus-without-user-activation 'none'"></iframe>
<!-- HTTP header: deny the capability for all subframes on this page -->
<!-- Permissions-Policy: focus-without-user-activation=() -->
// Inside the iframe, focus() still works normally during click handlers:
button.addEventListener('click', () => input.focus()); // works — user activation present
// But auto-focus at load time is blocked if the policy denies it:
window.addEventListener('load', () => input.focus()); // silently ignored if denied
references
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗