Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create steal-focus-explainer.md #852

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Conversation

siliu1
Copy link
Member

@siliu1 siliu1 commented Aug 20, 2024

explainer for preventing iframe from getting keyboard focus programmatically.

StealFocus/steal-focus-explainer.md Outdated Show resolved Hide resolved
StealFocus/steal-focus-explainer.md Outdated Show resolved Hide resolved
StealFocus/steal-focus-explainer.md Show resolved Hide resolved
StealFocus/steal-focus-explainer.md Outdated Show resolved Hide resolved
StealFocus/steal-focus-explainer.md Outdated Show resolved Hide resolved
Adress PR comments.
@siliu1 siliu1 marked this pull request as ready for review August 22, 2024 16:36
StealFocus/steal-focus-explainer.md Outdated Show resolved Hide resolved
StealFocus/steal-focus-explainer.md Outdated Show resolved Hide resolved
StealFocus/steal-focus-explainer.md Outdated Show resolved Hide resolved
It is not a goal of this proposal to prevent non-programmatic focus in iframes.

## Use Cases
Some web apps such as Microsoft Teams apps are often run inside an iFrame in the web. This has resulted in some poor user experience issues for keyboard users. For example: in Teams it’s possible to view notifications of apps in the ‘Activity’ section. When a user navigates to a notification from an app (such as Viva Engage) that app can ‘steal focus’ from the user and place it in their app. This prevents the user from their keyboard to navigate through their notifications because an app can ‘steal’ focus at any time. Keyboard users' expectations are that their keyboard focus doesn’t jump around unexpectedly.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused about the mechanism triggering the focus stealing in Teams. What aspect of the user navigating to the app notification allows the iframe to steal focus? Maybe we're newly appending the iframe to the DOM, and it takes focus during initialization? Are there technical reasons it's hard to have the iframe code stop trying to take focus, or is that more of an issue stemming from organizational boundaries?

If there's an additional example we can point to of this issue on the web, outside of Teams, that might also be helpful to motivate this proposal.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a PoC page to demonstrate the issue.

I am still searching for the additional example of this issue. Will update the explainer once I found it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand technically that a frame can steal focus by just calling focus() on something. What I'm curious about is why is the Viva app (for example) doing this? Until we have disallowprogrammaticfocus, would a reasonable workaround be to ask the Viva team to stop calling focus() when loaded? Or are there other contexts where the same content is loaded where calling focus() does make sense?

StealFocus/steal-focus-explainer.md Outdated Show resolved Hide resolved
StealFocus/steal-focus-explainer.md Outdated Show resolved Hide resolved
StealFocus/steal-focus-explainer.md Outdated Show resolved Hide resolved
StealFocus/steal-focus-explainer.md Outdated Show resolved Hide resolved
</html>
```

This alternative was not selected as the preferred one, because we think that the default option (policy not set) is against current behavior and may have compatibility risk.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like it would be web compatible if we allowed this functionality to be controlled with a new permissions policy whose default value is '*'.

Not sure if there are any permissions policies with the fully permissive default like that. But if that's workable it could be a lighter weight approach versus a whole new attribute, and it could be easier for sites to adopt if they're already using permissions policies to control other things.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I get it. Are you suggesting we create a new policy like disallow-programmatic-focus?

<iframe src=""
        allow="disallow-programmatic-focus *;">
</iframe>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to match the polarity of existing permissions policies, I think we'd want to have the polarity the other way around, so that denying the policy disables the functionality. So it would be a policy like take-programmatic-focus, with a default allowlist of '*' (for backwards compatibility). Then, to restrict it for iframes, a page could either be served with the HTTP header Feature-Policy: take-programmatic-focus 'none', or use the allow attribute on the iframe:
<iframe src="" allow="take-programmatic-focus none;"></iframe>.

Per the email thread about this, it sounds like Ian may have proposed something along these lines?

Add a demo page and a image for nested iframe.
<html>
<body>
<h1>Focus Steal Sample</h1>
<p>Click on the "Load frame" button below to see focus being stole by the iframed page. You will see the focus rect move into the frame after it loads.</p>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<p>Click on the "Load frame" button below to see focus being stole by the iframed page. You will see the focus rect move into the frame after it loads.</p>
<p>Click on the "Load frame" button below to see focus being stolen by the iframed page. You will see the focus rect move into the frame after it loads.</p>

It is not a goal of this proposal to prevent non-programmatic focus in iframes.

## Use Cases
Some web apps such as Microsoft Teams apps are often run inside an iFrame in the web. This has resulted in some poor user experience issues for keyboard users. For example: in Teams it’s possible to view notifications of apps in the ‘Activity’ section. When a user navigates to a notification from an app (such as Viva Engage) that app can ‘steal focus’ from the user and place it in their app. This prevents the user from their keyboard to navigate through their notifications because an app can ‘steal’ focus at any time. Keyboard users' expectations are that their keyboard focus doesn’t jump around unexpectedly.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand technically that a frame can steal focus by just calling focus() on something. What I'm curious about is why is the Viva app (for example) doing this? Until we have disallowprogrammaticfocus, would a reasonable workaround be to ask the Viva team to stop calling focus() when loaded? Or are there other contexts where the same content is loaded where calling focus() does make sense?

</html>
```

This alternative was not selected as the preferred one, because we think that the default option (policy not set) is against current behavior and may have compatibility risk.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to match the polarity of existing permissions policies, I think we'd want to have the polarity the other way around, so that denying the policy disables the functionality. So it would be a policy like take-programmatic-focus, with a default allowlist of '*' (for backwards compatibility). Then, to restrict it for iframes, a page could either be served with the HTTP header Feature-Policy: take-programmatic-focus 'none', or use the allow attribute on the iframe:
<iframe src="" allow="take-programmatic-focus none;"></iframe>.

Per the email thread about this, it sounds like Ian may have proposed something along these lines?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants