Skip to content

Conversation

@jandrade
Copy link
Member

@jandrade jandrade commented Dec 9, 2025

Summary:

This PR changes the dismissEnabled behavior to close/dismiss the popover once
the focus moves outside of it.

Issue: https://khanacademy.atlassian.net/browse/WB-2147

Test plan:

Navigate to the DismissEnabled story and test the following scenarios:

  • Tabbing before the trigger element should dismiss the popover.
  • Tabbing after the last focusable element inside the popover should dismiss the popover.

/?path=/docs/packages-popover-popover--docs#dismiss-enabled

Screen.Recording.2025-12-09.at.2.47.31.PM.mov

Juan Andrade added 2 commits December 9, 2025 14:43
@jandrade jandrade self-assigned this Dec 9, 2025
@changeset-bot
Copy link

changeset-bot bot commented Dec 9, 2025

🦋 Changeset detected

Latest commit: 0e53eba

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

This PR includes changesets to release 1 package
Name Type
@khanacademy/wonder-blocks-popover 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
Copy link
Contributor

github-actions bot commented Dec 9, 2025

Size Change: +11 B (+0.01%)

Total Size: 109 kB

Filename Size Change
packages/wonder-blocks-popover/dist/es/index.js 4.32 kB +11 B (+0.26%)
ℹ️ View Unchanged
Filename Size
packages/wonder-blocks-accordion/dist/es/index.js 3 kB
packages/wonder-blocks-announcer/dist/es/index.js 1.74 kB
packages/wonder-blocks-badge/dist/es/index.js 2.02 kB
packages/wonder-blocks-banner/dist/es/index.js 2.01 kB
packages/wonder-blocks-birthday-picker/dist/es/index.js 1.92 kB
packages/wonder-blocks-breadcrumbs/dist/es/index.js 755 B
packages/wonder-blocks-button/dist/es/index.js 4.25 kB
packages/wonder-blocks-card/dist/es/index.js 1.06 kB
packages/wonder-blocks-cell/dist/es/index.js 2.18 kB
packages/wonder-blocks-clickable/dist/es/index.js 2.66 kB
packages/wonder-blocks-core/dist/es/index.js 2.48 kB
packages/wonder-blocks-data/dist/es/index.js 5.48 kB
packages/wonder-blocks-dropdown/dist/es/index.js 19.5 kB
packages/wonder-blocks-form/dist/es/index.js 6.2 kB
packages/wonder-blocks-grid/dist/es/index.js 1.24 kB
packages/wonder-blocks-icon-button/dist/es/index.js 3.2 kB
packages/wonder-blocks-icon/dist/es/index.js 1.91 kB
packages/wonder-blocks-labeled-field/dist/es/index.js 3.48 kB
packages/wonder-blocks-layout/dist/es/index.js 1.63 kB
packages/wonder-blocks-link/dist/es/index.js 1.52 kB
packages/wonder-blocks-modal/dist/es/index.js 7.06 kB
packages/wonder-blocks-pill/dist/es/index.js 1.31 kB
packages/wonder-blocks-progress-spinner/dist/es/index.js 1.48 kB
packages/wonder-blocks-search-field/dist/es/index.js 1.1 kB
packages/wonder-blocks-styles/dist/es/index.js 464 B
packages/wonder-blocks-switch/dist/es/index.js 1.55 kB
packages/wonder-blocks-tabs/dist/es/index.js 3.74 kB
packages/wonder-blocks-testing-core/dist/es/index.js 3.25 kB
packages/wonder-blocks-testing/dist/es/index.js 978 B
packages/wonder-blocks-theming/dist/es/index.js 384 B
packages/wonder-blocks-timing/dist/es/index.js 1.37 kB
packages/wonder-blocks-tokens/dist/es/index.js 5.01 kB
packages/wonder-blocks-toolbar/dist/es/index.js 906 B
packages/wonder-blocks-tooltip/dist/es/index.js 6.4 kB
packages/wonder-blocks-typography/dist/es/index.js 1.57 kB

compressed-size-action

@github-actions
Copy link
Contributor

github-actions bot commented Dec 9, 2025

npm Snapshot: Published

🎉 Good news!! We've packaged up the latest commit from this PR (812aefe) and published all packages with changesets to npm.

You can install the packages in frontend by running:

./dev/tools/deploy_wonder_blocks.js --tag="PR2896"

Packages can also be installed manually by running:

pnpm add @khanacademy/wonder-blocks-<package-name>@PR2896

@github-actions
Copy link
Contributor

github-actions bot commented Dec 9, 2025

A new build was pushed to Chromatic! 🚀

https://5e1bf4b385e3fb0020b7073c-txblpvpzqf.chromatic.com/

Chromatic results:

Metric Total
Captured snapshots 447
Tests with visual changes 0
Total stories 752
Inherited (not captured) snapshots [TurboSnap] 0
Tests on the build 447

@jandrade jandrade marked this pull request as ready for review December 9, 2025 19:48
@khan-actions-bot khan-actions-bot requested a review from a team December 9, 2025 19:48
@khan-actions-bot
Copy link
Contributor

Gerald

Required Reviewers
  • @Khan/wonder-blocks for changes to .changeset/wise-hairs-vanish.md, __docs__/wonder-blocks-popover/popover.stories.tsx, packages/wonder-blocks-popover/src/components/focus-manager.tsx, packages/wonder-blocks-popover/src/components/popover.tsx, packages/wonder-blocks-popover/src/components/__tests__/focus-manager.test.tsx, packages/wonder-blocks-popover/src/components/__tests__/popover.test.tsx

Don't want to be involved in this pull request? Comment #removeme and we won't notify you of further changes.

Copy link
Member

@beaesguerra beaesguerra 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!

});
});

// TODO(FEI-5533): Key press events aren't working correctly with
Copy link
Member

Choose a reason for hiding this comment

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

Thanks for enabling this to work again!

Comment on lines +505 to +584
it("should close the popover when the user tabs before the trigger element", async () => {
// Arrange
render(
<Popover
dismissEnabled={true}
placement="top"
content={
<PopoverContent
title="Title"
content="content"
closeButtonVisible={true}
/>
}
>
{({open}: any) => (
<button data-anchor onClick={open}>
Open default popover
</button>
)}
</Popover>,
);

// open the popover
await userEvent.click(
await screen.findByRole("button", {
name: "Open default popover",
}),
);

// Act
// Focus on the reference element
await userEvent.tab({shift: true});
// Focus on the previous element before the popover (triggers
// closing the popover)
await userEvent.tab({shift: true});

// Assert
await waitFor(() => {
expect(screen.queryByText("Title")).not.toBeInTheDocument();
});
});

it("should close the popover when the user tabs after the last focusable element inside the popover", async () => {
// Arrange
render(
<div>
<Popover
dismissEnabled={true}
placement="top"
content={
<PopoverContent
title="Title"
content="content"
closeButtonVisible={true}
/>
}
>
<Button>Open default popover</Button>
</Popover>
<Button>Next button outside</Button>
</div>,
);

// open the popover
// open the popover by focusing on the trigger element
await userEvent.click(
await screen.findByRole("button", {
name: "Open default popover",
}),
);

// Focus on the last focusable element inside the popover (dismiss button)
await userEvent.tab();

// Focus on the next element after the popover
await userEvent.tab();

// Assert
expect(screen.queryByText("Title")).not.toBeInTheDocument();
});
Copy link
Member

Choose a reason for hiding this comment

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

Should we have tests for when dismissEnabled={false}, the popover isn't closed on focus out?

}

// The user is tabbing out of the popover.
if (e.key === "Tab" && !e.shiftKey) {
Copy link
Member

Choose a reason for hiding this comment

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

Could use the keys.tab from wonder-blocks-core!

}

// The user is tabbing before the trigger element.
if (e.key === "Tab" && e.shiftKey) {
Copy link
Member

Choose a reason for hiding this comment

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

Same suggestion about using the keys constant!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants