Skip to content

Pin aria-live announcer to top:0; left:0 to avoid scroll overflow#3383

Merged
BryanValverdeU merged 3 commits into
microsoft:masterfrom
alibaba:fix/aria-live-announcer-scroll-overflow
Jun 29, 2026
Merged

Pin aria-live announcer to top:0; left:0 to avoid scroll overflow#3383
BryanValverdeU merged 3 commits into
microsoft:masterfrom
alibaba:fix/aria-live-announcer-scroll-overflow

Conversation

@daxiang94

@daxiang94 daxiang94 commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Problem

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.

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: 0 so the absolute element sits at the top-left of its containing block and never extends the scroll area.

  • Element remains invisible: clip-path: inset(100%) + 1×1 size + overflow: hidden
  • aria-live continues to announce textContent changes — no behavior change for screen readers

Files 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 existing toEqual assertions)

Checklist

  • Code passes linting
  • Pre-commit hooks passed
  • Follows existing code patterns and conventions

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.
@daxiang94

Copy link
Copy Markdown
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.
div.style.height = '1px';
div.style.overflow = 'hidden';
div.style.position = 'absolute';
div.style.top = '0';

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@BryanValverdeU please take a look

@BryanValverdeU
BryanValverdeU merged commit e610bdb into microsoft:master Jun 29, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants