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

Overlay: only prevent focus on open when component is open #5636

Merged
merged 8 commits into from
Feb 8, 2025

Conversation

ktravers
Copy link
Contributor

@ktravers ktravers commented Jan 31, 2025

Depends on https://github.com/github/github/pull/361151
Related to https://github.com/github/github/pull/360074

This PR updates the useOpenAndCloseFocus hook to apply focus to the given return ref element when the preventFocusOnOpen prop is also given.

Previously, if preventFocusOnOpen argument was given, then focus was not applied as expected to the given return ref element, resulting in accessibility issues. With these changes, focus will be applied to the given return ref in all cases, regardless of whether preventFocusOnOpen argument is included, allowing these arguments to be used together without any unexpected conflicts.

Currently, these change affect the Overlay component only, as the sole consumer of the useOpenAndCloseFocus hook.

Note

The preventFocusOnOpen prop is currently undocumented in the Overlay component. It's unclear to me whether this is intentional. I opted not to document it for now, but would appreciate reviewers' thoughts on that.

Changelog

New

  • Additional tests for useOpenAndCloseFocus hook
  • Additional tests for Overlay component (which depends on useOpenAndCloseFocus hook)
  • PreventFocusOnOpen story in Overlay.dev.stories.tsx

Changed

  • Logic within useOpenAndCloseFocus hook

Removed

N/A

Rollout strategy

  • Patch release
  • Minor release
  • Major release; if selected, include a written rollout or migration plan
  • None; if selected, include a brief description as to why

Testing & Reviewing

  • Run npm test Overlay to run component tests
  • Run npm test hooks/useOpenAndCloseFocus to run hook tests
  • View Overlay component in Storybook (Overlay > dev > PreventFocusOnOpen)

Merge checklist

Otherwise, prevents focus from returning to given returnFocusRef.
@ktravers ktravers self-assigned this Jan 31, 2025
Copy link

changeset-bot bot commented Jan 31, 2025

🦋 Changeset detected

Latest commit: 868ece3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@primer/react Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added the integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm label Jan 31, 2025
Copy link
Contributor

👋 Hi, this pull request contains changes to the source code that github/github depends on. If you are GitHub staff, we recommend testing these changes with github/github using the integration workflow. Thanks!

Copy link
Contributor

github-actions bot commented Jan 31, 2025

size-limit report 📦

Path Size
packages/react/dist/browser.esm.js 105.33 KB (-0.09% 🔽)
packages/react/dist/browser.umd.js 105.81 KB (-0.02% 🔽)

@github-actions github-actions bot temporarily deployed to storybook-preview-5636 January 31, 2025 18:18 Inactive
@github-actions github-actions bot temporarily deployed to storybook-preview-5636 February 4, 2025 03:58 Inactive
@github-actions github-actions bot requested a deployment to storybook-preview-5636 February 5, 2025 02:24 Abandoned
@github-actions github-actions bot temporarily deployed to storybook-preview-5636 February 5, 2025 02:38 Inactive
@github-actions github-actions bot requested a deployment to storybook-preview-5636 February 5, 2025 02:51 Abandoned
@github-actions github-actions bot temporarily deployed to storybook-preview-5636 February 5, 2025 03:05 Inactive
@github-actions github-actions bot temporarily deployed to storybook-preview-5636 February 5, 2025 03:21 Inactive
Comment on lines -19 to -21
if (preventFocusOnOpen) {
return
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These lines are the most critical change. By returning early here, we prevent the hook from ever applying focus to the given returnFocusRef. This results in unexpected behavior in components like Overlay when preventFocusOnOpen and returnFocusRef props are used together -- specifically, return focus is not applied as expected.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also worth noting -- preventFocusOnOpen is currently undocumented. However, this has not prevented it from being used in production (for example, in the case that inspired me to open this PR).

Should this prop be documented? 🤔

On the one hand, I suspect we don't want to encourage its use. However, by not documenting it, users are more susceptible to "misusing" the prop, resulting in unexpected behavior. Maybe that's not a concern if these changes are merged, but I wanted to ask anyway since it seems worth considering.

Copy link
Contributor

Choose a reason for hiding this comment

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

By returning early here, we prevent the hook from ever applying focus to the given returnFocusRef

I see! So that meant that returnRef wasn't defined if preventFocusOnOpen === true?

Should this prop be documented?

I think we have some pretty old and mostly hidden docs for this hook in primer.style. It doesn't really explain too much, so I think it's worth updating! Ideally, we'll need to rely on this hook even less once we utilize popover in Overlay.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So that meant that returnRef wasn't defined if preventFocusOnOpen === true?

returnRef was defined, but returnRef.focus() was never called if preventFocusOnOpen === true. It just sort of failed silently 😞

I think it's worth updating! Ideally, we'll need to rely on this hook even less once we utilize popover in Overlay.

Cool, makes sense! Also thanks for linking to the hooks docs. I never checked outside the component docs 🤦‍♀️ I'll make sure preventFocusOnOpen is documented in both places 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hook docs update: primer/design#926

Copy link
Contributor Author

Choose a reason for hiding this comment

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

component docs updated here: 868ece3

@github-actions github-actions bot requested a deployment to storybook-preview-5636 February 5, 2025 03:38 Abandoned
@github-actions github-actions bot temporarily deployed to storybook-preview-5636 February 5, 2025 03:52 Inactive
@ktravers ktravers requested a review from TylerJDev February 5, 2025 05:19
@github-actions github-actions bot temporarily deployed to storybook-preview-5636 February 5, 2025 05:21 Inactive
@github-actions github-actions bot added integration-tests: failing Changes in this PR cause breaking changes in gh/gh and removed integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm labels Feb 5, 2025
@ktravers
Copy link
Contributor Author

ktravers commented Feb 6, 2025

Taking back to draft while I work on integration tests.

@ktravers ktravers marked this pull request as draft February 6, 2025 02:43
@ktravers
Copy link
Contributor Author

ktravers commented Feb 6, 2025

Did some debugging on the integration test branch, and turns out there's a component in github/github that relies on the current (and I would argue, incorrect) behavior, where no focus is applied even on close if preventFocusOnOpen prop is given. See this commit for full details: https://github.com/github/github/pull/361072/commits/b2d5902cdcf7a6d082dcf3de18b491d2f3f3abc3

I'm going to test whether the change above works with the current Overlay behavior. If yes, then I'll ship the gh/gh PR first, then come back to this one. If no, then I'll need to chat with maintainers about options for moving forward (if any).

[update] Good news: the changes are backwards compatible. See https://github.com/github/github/pull/361151.

@github-actions github-actions bot added integration-tests: passing Changes in this PR do NOT cause breaking changes in gh/gh and removed integration-tests: failing Changes in this PR cause breaking changes in gh/gh labels Feb 6, 2025
@ktravers ktravers marked this pull request as ready for review February 6, 2025 04:04
@primer-integration
Copy link

👋 Hi from github/github! Your integration PR is ready: https://github.com/github/github/pull/361153

@primer-integration
Copy link

🟢 golden-jobs completed with status success.

@@ -16,18 +16,21 @@ export function useOpenAndCloseFocus({
preventFocusOnOpen,
}: UseOpenAndCloseFocusSettings): void {
useEffect(() => {
if (preventFocusOnOpen) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering what exactly preventFocusOnOpen was being used for 🤔 In your use case, were you utilizing this prop? Seems counter intuitive, but I might not be seeing the full picture 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The two cases I'm aware of were both used to keep focus on the "entrypoint" element when an overlay was opened:

  1. Copilot chat panel. I think it was used by mistake here, because there was also code to apply focus to an input inside the overlay after it was opened 🤦‍♀️ I recently removed it.
  2. Autocomplete. Here it was used very intentionally to keep focus on the textarea, where the user is typing, while the autocomplete dialog is open.

@github-actions github-actions bot added the integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm label Feb 6, 2025
Copy link
Contributor

github-actions bot commented Feb 6, 2025

👋 Hi, there are new commits since the last successful integration test. We recommend running the integration workflow once more, unless you are sure the new changes do not affect github/github. Thanks!

ktravers added a commit to primer/design that referenced this pull request Feb 6, 2025
camertron pushed a commit to primer/design that referenced this pull request Feb 6, 2025
…ay hooks (#926)

* document preventFocusOnOpen prop

Related: primer/react#5636

* document prop in useOverlay hook
Copy link
Contributor

@TylerJDev TylerJDev left a comment

Choose a reason for hiding this comment

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

Looks good to me! Thank you for all the changes and updates to the docs, truly appreciate it ✨

@ktravers ktravers removed the integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm label Feb 7, 2025
@ktravers ktravers added this pull request to the merge queue Feb 8, 2025
Merged via the queue into main with commit c2165af Feb 8, 2025
47 checks passed
@ktravers ktravers deleted the ktravers-patch-1 branch February 8, 2025 01:47
@primer primer bot mentioned this pull request Feb 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integration-tests: passing Changes in this PR do NOT cause breaking changes in gh/gh
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants