Skip to content

Conversation

@Rajdeepc
Copy link
Contributor

@Rajdeepc Rajdeepc commented Aug 25, 2025

Description

This PR implements body scroll blocking functionality for modal and page overlays to prevent background content from scrolling while overlays are open

Motivation and context

  • User Experience: Prevents confusing background scrolling while modal dialogs are open
  • Accessibility: Ensures focus remains within modal content and prevents navigation confusion
  • Aligns with standard web platform behavior for modal overlays

Changes Made

Core Functionality

  • Added manageBodyScroll() method in OverlayStack.ts that automatically blocks body scroll when modal or page overlays are present
  • Body scroll state management with bodyScrollBlocked flag and originalBodyOverflow preservation
  • Automatic restoration of original body overflow when all modal/page overlays are closed

Implementation Details

  • Scroll blocking triggers: Activates when any overlay with type: 'modal' or type: 'page' is added to the stack
  • Scroll restoration: Only restores when all modal/page overlays are removed (maintains blocking if multiple overlays exist)
  • State preservation: Stores and restores the original document.body.style.overflow value

Related issue(s)

  • fixes SWC 1021

Screenshots (if appropriate)

Desktop
Screenshot 2025-08-25 at 3 23 33 PM

Mobile
Screenshot 2025-08-25 at 3 24 22 PM


Author's checklist

  • I have read the CONTRIBUTING and PULL_REQUESTS documents.
  • I have reviewed at the Accessibility Practices for this feature, see: Aria Practices
  • I have added automated tests to cover my changes.
  • I have included a well-written changeset if my change needs to be published.
  • I have included updated documentation if my change required it.

Reviewer's checklist

  • Includes a Github Issue with appropriate flag or Jira ticket number without a link
  • Includes thoughtfully written changeset if changes suggested include patch, minor, or major features
  • Automated tests cover all use cases and follow best practices for writing
  • Validated on all supported browsers
  • All VRTs are approved before the author can update Golden Hash

Manual review test cases

  • "modal" and "page" overlay should not have page scroll

    1. Go here
    2. Click on Open Modal Button
    3. Expect the page has no scroll

Device review

  • Did it pass in Desktop?
  • Did it pass in (emulated) Mobile?
  • Did it pass in (emulated) iPad?

@changeset-bot
Copy link

changeset-bot bot commented Aug 25, 2025

🦋 Changeset detected

Latest commit: efabcf9

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

This PR includes changesets to release 84 packages
Name Type
@spectrum-web-components/overlay Minor
@spectrum-web-components/combobox Minor
@spectrum-web-components/contextual-help Minor
@spectrum-web-components/menu Minor
@spectrum-web-components/picker Minor
@spectrum-web-components/popover Minor
@spectrum-web-components/tooltip Minor
@spectrum-web-components/story-decorator Minor
@spectrum-web-components/bundle Minor
@spectrum-web-components/truncated Minor
@spectrum-web-components/breadcrumbs Minor
@spectrum-web-components/custom-vars-viewer Minor
example-project-rollup Patch
example-project-webpack Patch
@spectrum-web-components/action-menu Minor
@spectrum-web-components/action-bar Minor
@spectrum-web-components/card Minor
documentation Patch
@spectrum-web-components/vrt-compare Minor
@spectrum-web-components/eslint-plugin Minor
@spectrum-web-components/accordion Minor
@spectrum-web-components/action-button Minor
@spectrum-web-components/action-group Minor
@spectrum-web-components/alert-banner Minor
@spectrum-web-components/alert-dialog Minor
@spectrum-web-components/asset Minor
@spectrum-web-components/avatar Minor
@spectrum-web-components/badge Minor
@spectrum-web-components/button-group Minor
@spectrum-web-components/button Minor
@spectrum-web-components/checkbox Minor
@spectrum-web-components/clear-button Minor
@spectrum-web-components/close-button Minor
@spectrum-web-components/coachmark Minor
@spectrum-web-components/color-area Minor
@spectrum-web-components/color-field Minor
@spectrum-web-components/color-handle Minor
@spectrum-web-components/color-loupe Minor
@spectrum-web-components/color-slider Minor
@spectrum-web-components/color-wheel Minor
@spectrum-web-components/dialog Minor
@spectrum-web-components/divider Minor
@spectrum-web-components/dropzone Minor
@spectrum-web-components/field-group Minor
@spectrum-web-components/field-label Minor
@spectrum-web-components/help-text Minor
@spectrum-web-components/icon Minor
@spectrum-web-components/icons-ui Minor
@spectrum-web-components/icons-workflow Minor
@spectrum-web-components/icons Minor
@spectrum-web-components/iconset Minor
@spectrum-web-components/illustrated-message Minor
@spectrum-web-components/infield-button Minor
@spectrum-web-components/link Minor
@spectrum-web-components/meter Minor
@spectrum-web-components/modal Minor
@spectrum-web-components/number-field Minor
@spectrum-web-components/picker-button Minor
@spectrum-web-components/progress-bar Minor
@spectrum-web-components/progress-circle Minor
@spectrum-web-components/radio Minor
@spectrum-web-components/search Minor
@spectrum-web-components/sidenav Minor
@spectrum-web-components/slider Minor
@spectrum-web-components/split-view Minor
@spectrum-web-components/status-light Minor
@spectrum-web-components/swatch Minor
@spectrum-web-components/switch Minor
@spectrum-web-components/table Minor
@spectrum-web-components/tabs Minor
@spectrum-web-components/tags Minor
@spectrum-web-components/textfield Minor
@spectrum-web-components/thumbnail Minor
@spectrum-web-components/toast Minor
@spectrum-web-components/top-nav Minor
@spectrum-web-components/tray Minor
@spectrum-web-components/underlay Minor
@spectrum-web-components/base Minor
@spectrum-web-components/grid Minor
@spectrum-web-components/opacity-checkerboard Minor
@spectrum-web-components/reactive-controllers Minor
@spectrum-web-components/shared Minor
@spectrum-web-components/styles Minor
@spectrum-web-components/theme Minor

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

@Rajdeepc Rajdeepc self-assigned this Aug 25, 2025
@Rajdeepc Rajdeepc added bug Something isn't working Component: Overlay labels Aug 25, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Aug 25, 2025

📚 Branch Preview

🔍 Visual Regression Test Results

When a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:

Deployed to Azure Blob Storage: pr-5710

If the changes are expected, update the current_golden_images_cache hash in the circleci config to accept the new images. Instructions are included in that file.
If the changes are unexpected, you can investigate the cause of the differences and update the code accordingly.

@github-actions
Copy link
Contributor

github-actions bot commented Aug 25, 2025

Tachometer results

Chrome

overlay permalink

basic-test

Version Bytes Avg Time vs remote vs branch
npm latest 822 kB 441.22ms - 447.90ms - faster ✔
1% - 4%
6.02ms - 19.21ms
branch 790 kB 451.49ms - 462.86ms slower ❌
1% - 4%
6.02ms - 19.21ms
-

directive-test permalink

Version Bytes Avg Time vs remote vs branch
npm latest 826 kB 27.12ms - 28.32ms - faster ✔
5% - 10%
1.46ms - 3.14ms
branch 794 kB 29.43ms - 30.61ms slower ❌
5% - 11%
1.46ms - 3.14ms
-

element-test permalink

Version Bytes Avg Time vs remote vs branch
npm latest 816 kB 360.81ms - 367.33ms - faster ✔
1% - 4%
4.00ms - 13.88ms
branch 783 kB 369.30ms - 376.72ms slower ❌
1% - 4%
4.00ms - 13.88ms
-

lazy-test permalink

Version Bytes Avg Time vs remote vs branch
npm latest 616 kB 47.69ms - 49.05ms - faster ✔
0% - 6%
0.09ms - 2.81ms
branch 585 kB 48.65ms - 51.00ms slower ❌
0% - 6%
0.09ms - 2.81ms
-
Firefox

overlay permalink

basic-test

Version Bytes Avg Time vs remote vs branch
npm latest 822 kB 773.28ms - 783.32ms - unsure 🔍
-1% - +2%
-5.59ms - +14.07ms
branch 790 kB 765.61ms - 782.51ms unsure 🔍
-2% - +1%
-14.07ms - +5.59ms
-

directive-test permalink

Version Bytes Avg Time vs remote vs branch
npm latest 826 kB 45.27ms - 47.45ms - faster ✔
2% - 8%
1.13ms - 3.87ms
branch 794 kB 48.03ms - 49.69ms slower ❌
2% - 8%
1.13ms - 3.87ms
-

element-test permalink

Version Bytes Avg Time vs remote vs branch
npm latest 816 kB 615.93ms - 629.83ms - unsure 🔍
-1% - +1%
-8.20ms - +8.44ms
branch 783 kB 618.18ms - 627.34ms unsure 🔍
-1% - +1%
-8.44ms - +8.20ms
-

lazy-test permalink

Version Bytes Avg Time vs remote vs branch
npm latest 616 kB 87.90ms - 90.14ms - faster ✔
3% - 7%
2.72ms - 6.40ms
branch 585 kB 92.12ms - 95.04ms slower ❌
3% - 7%
2.72ms - 6.40ms
-

@Rajdeepc Rajdeepc marked this pull request as ready for review August 25, 2025 09:57
@Rajdeepc Rajdeepc requested a review from a team as a code owner August 25, 2025 09:57
@Rajdeepc Rajdeepc added the Status: Ready for review PR ready for review or re-review. label Aug 25, 2025
Copy link
Contributor

@nikkimk nikkimk left a comment

Choose a reason for hiding this comment

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

LGTM with one nit on the changeset.

'@spectrum-web-components/overlay': minor
---

**Fixed** : add body scroll prevention for modal and page overlays. Automatically block body scroll when modal or page overlays are open and restore the original scroll state when they are closed, improving user experience and accessibility for modal dialogs.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Our writing changeset docs recommend using past tense.

Suggested change
**Fixed** : add body scroll prevention for modal and page overlays. Automatically block body scroll when modal or page overlays are open and restore the original scroll state when they are closed, improving user experience and accessibility for modal dialogs.
**Fixed** : Added body scroll prevention for modal and page overlays. Overlay automatically blocks body scroll when modal or page overlays are open and restores the original scroll state when they are closed, improving user experience and accessibility for modal dialogs.

Copy link
Contributor

@rubencarvalho rubencarvalho left a comment

Choose a reason for hiding this comment

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

Solution looks great! 🚀 I just left one small comment about creating a more “e2e” style test to verify the scroll blocking.

).to.be.false;
});

it('blocks body scroll when modal overlay is opened and restores when closed', async function () {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: could we also add a behavioral test that verifies the page actually can’t scroll while the modal is open (and can again after it closes)? Right now we’re checking the body overflow style, which is fine, but it’s still an implementation detail. I was thinking we could create a long enough page, attempt a scroll (e.g. window.scrollTo), and assert on window.scrollY.

Copy link
Contributor Author

@Rajdeepc Rajdeepc Aug 27, 2025

Choose a reason for hiding this comment

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

Certainly we can. Excellent suggestion!. We haven't explored these tests yet on our patterns but would love to add these for others too.

@Rajdeepc Rajdeepc added Needs Re-review and removed Status: Ready for review PR ready for review or re-review. labels Aug 27, 2025
Copy link
Contributor

@blunteshwar blunteshwar left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@rubencarvalho rubencarvalho left a comment

Choose a reason for hiding this comment

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

One little await and we can 🚢 it!


// Close modal overlay
const closed = oneEvent(modalTrigger, 'sp-closed');
sendMouse({
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
sendMouse({
await sendMouse({

@Rajdeepc Rajdeepc requested a review from rubencarvalho August 28, 2025 07:40
@Rajdeepc Rajdeepc merged commit ee1bae6 into main Aug 28, 2025
24 checks passed
@Rajdeepc Rajdeepc deleted the rajdeep/body-scroll-overlay branch August 28, 2025 09:56
lehelen19 pushed a commit to lehelen19/spectrum-web-components that referenced this pull request Oct 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working Component: Overlay

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants