Skip to content

fix: finish Sheet exit once the scroll rests at the exit position - #10835

Closed
mhasanince wants to merge 2 commits into
adobe:mainfrom
mhasanince:fix/sheet-exit-scrollend
Closed

mhasanince wants to merge 2 commits into
adobe:mainfrom
mhasanince:fix/sheet-exit-scrollend

Conversation

@mhasanince

@mhasanince mhasanince commented Oct 22, 2026 •

Copy link
Copy Markdown

Closes #10813

Summary

A closing Sheet only finishes its exit when the IntersectionObserver reports the content at ratio 0. On busy CI runners (GitHub Actions, Chrome) that last report sometimes never arrives, so the overlay stays data-exiting over the page and blocks clicks, even though the sheet has already slid out.

Fix

onExit also resolves once the scroller fires scrollend at the exit position, or right away if it's already there. The react-aria-sheet-close event still works as before, this is only a fallback. We run the same change as a patch in our app.

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices
  • I understand every change in this PR and can explain why it's there.
  • If AI-assisted, I followed our AI contribution guidance and pointed my assistant at AGENTS.md.

AI use: I wrote this change with Claude Code, then reviewed and tested it myself.

📝 Test Instructions:

Added a browser test in Sheet.browser.test.tsx that closes an entered sheet while dropping the observer's ratio-0 entry. It fails on main and passes here in Chromium, Firefox and WebKit.

To try it in a browser, wrap IntersectionObserver so it drops entries with intersectionRatio === 0, open a Sheet, let it fully enter, then close it. On main the overlay stays in the DOM with data-exiting; on this branch it's removed.

🧢 Your Project:

Kordela

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the RAC label Oct 22, 2026
@yihuiliao

Copy link
Copy Markdown
Member

Seems like you need to sign the CLA

@mhasanince mhasanince closed this Oct 23, 2026
@mhasanince mhasanince reopened this Oct 23, 2026

@snowystinger snowystinger left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

On busy CI runners (GitHub Actions, Chrome) that last report sometimes never arrives, so the overlay stays data-exiting over the page and blocks clicks, even though the sheet has already slid out.

What does this mean? Why would it never arrive? shouldn't it be guaranteed even if maybe it's a frame or two slow? It seems like this would be a huge flaw in IntersectionObserver if this is true.

done();
}
};
let done = () => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

for easier reading, please move this declaration before where it is used

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Moved it up.

expect(triggerOnOpenChange).not.toHaveBeenCalled();
});

it('finishes closing once the exit scroll ends, even if the sheet is never reported hidden', async () => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should this test be a browser.test instead?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Makes sense, it mocks both scrolling and the observer. Moved it to Sheet.browser.test.tsx, which drops the ratio-0 entry from a real IntersectionObserver.

@mhasanince

Copy link
Copy Markdown
Author

Fair question, and I don't have a good answer. I'd expect the same, that the entry is delivered even if it's late. What we saw in Playwright traces from the failing CI runs: the sheet is gone from the screencast within ~150ms, and 5s later [data-sheet-scroll] sits at its exit position while the overlay is still data-exiting. I first suspected the observer being recreated mid-exit, but its dependencies are stable, so that seems unlikely. I couldn't reproduce it outside CI, so I can't tell whether it's Chromium on a starved runner or something in our app. If you'd rather not add a fallback without a root cause, that's fine, I can close this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
}

it('finishes closing once the exit scroll ends, even if the sheet is never reported hidden', async () => {
// Drop the observer's report that the sheet has left the viewport.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ok yeah, so this is what i was concerned about, if we have to forcibly drop this, then we don't yet have enough information. We need more research done on why it would be dropped in your CI.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed, without a root cause this isn't worth adding. I'll close this for now and reopen if I find out why it's dropped on our CI.

@mhasanince mhasanince closed this Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sheet stays exiting over the page when its IntersectionObserver's last report never comes

3 participants