Pin aria-live announcer to top:0; left:0 to avoid scroll overflow#3383
Merged
BryanValverdeU merged 3 commits intoJun 29, 2026
Merged
Conversation
createAriaLiveElement sets position:absolute on the screen-reader announcer container but leaves top/left unset. CSS resolves them to the element's static position (its place in normal flow), which sits after every other child of the announcer's eventual container. When that container has a non-trivial content height (typical app layouts), the absolute element contributes to the documentElement's scrollable overflow region and pushes out a small but visible scrollbar even though nothing is laid out beyond the viewport. Standard visually-hidden patterns anchor the element to a known viewport corner. Add top:0; left:0 so the absolute element sits at the top-left of its containing block and never extends the scroll area. The element remains invisible (clip-path:inset(100%) + 1x1 size + overflow:hidden) and aria-live continues to announce textContent changes. Repro: mount the editor in any host page where document body has a height >= viewport. A 1px-tall scrollbar appears even with no editor content overflowing.
Contributor
Author
|
@microsoft-github-policy-service agree company="Alibaba" |
Existing tests use toEqual to assert the exact shape of the announcer div's style object. Adding top/left in createAriaLiveElement breaks those assertions; add the same two properties to expected style blocks to match.
JiuqingSong
reviewed
Jun 26, 2026
| div.style.height = '1px'; | ||
| div.style.overflow = 'hidden'; | ||
| div.style.position = 'absolute'; | ||
| div.style.top = '0'; |
BryanValverdeU
approved these changes
Jun 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
createAriaLiveElementsetsposition: absoluteon the screen-reader announcer container but leavestop/leftunset. CSS resolves them to the element's static position — its place in normal flow, which sits after every other child of the announcer's eventual container.When that container has a non-trivial content height (typical app layouts), the absolute element contributes to the
documentElement's scrollable overflow region and pushes out a small but visible scrollbar even though nothing is laid out beyond the viewport.Repro
Mount the editor in any host page where document body has a layout height >= viewport. A 1px-tall scrollbar appears on
<html>even with no editor content overflowing. Removing the announcer from DOM at runtime confirms it is the cause.Fix
Standard visually-hidden patterns anchor the element to a known viewport corner. Add
top: 0; left: 0so the absolute element sits at the top-left of its containing block and never extends the scroll area.clip-path: inset(100%)+ 1×1 size +overflow: hiddenaria-livecontinues to announcetextContentchanges — no behavior change for screen readersFiles changed
packages/roosterjs-content-model-core/lib/utils/createAriaLiveElement.ts(+2)packages/roosterjs-content-model-core/test/coreApi/announce/announceTest.ts(+8, matching expected style in existingtoEqualassertions)Checklist