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

  1. Focus Demo

    Two iframes — one with focus-without-user-activation allowed, one denied — both trying to call focus() on a button automatically. Shows which succeeds.

  2. Policy Reference

    Default allowlist, iframe sandbox interaction, and recommended header patterns for embedding third-party content safely.

  3. 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.

  4. 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.

  5. 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-iframe allow="" attribute. Plus a lint that flags risky combinations.

  6. Capability fallback explorer

    Choose an embed policy, replay load-time versus user-activated focus attempts, and generate the matching Permissions-Policy header or iframe fallback for production embeds.

  7. Production Recipe

    Three real deployment scenarios — chat embed, media player, and widget host — each with the recommended HTTP header, iframe allow attribute, a live policy probe using document.featurePolicy, and a focus-without-gesture test that shows whether the policy is actually enforced in your browser.

  8. 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.featurePolicy API, 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 ↗