Skip to content

Fix auto-resize destroying horizontal scroll positions#567

Merged
ochafik merged 2 commits intomodelcontextprotocol:mainfrom
mel-anthropic:mel/fix-auto-resize-scroll-clamping
Mar 26, 2026
Merged

Fix auto-resize destroying horizontal scroll positions#567
ochafik merged 2 commits intomodelcontextprotocol:mainfrom
mel-anthropic:mel/fix-auto-resize-scroll-clamping

Conversation

@mel-anthropic
Copy link
Copy Markdown
Contributor

@mel-anthropic mel-anthropic commented Mar 25, 2026

Summary

Fix a bug where the SDK's auto-resize measurement permanently destroys horizontal scroll positions in MCP apps during viewport transitions (e.g. inline ↔ fullscreen).

Problem

setupSizeChangedNotifications() temporarily sets document.documentElement.style.width = 'fit-content' on every ResizeObserver callback to measure intrinsic content width. For responsive apps that derive their width from the container (width: 100%, flex: 1, etc.), fit-content resolves to 0px.

The getBoundingClientRect() call forces a synchronous reflow at 0px width. During this reflow, the browser clamps scrollLeft on all horizontal scroll containers to 0 (since scrollLeft cannot exceed scrollWidth - clientWidth, which is 0). When the style is restored, scrollLeft stays clamped — the browser does not un-clamp it.

This manifests as horizontal scroll views losing their position whenever the viewport resizes, which is most visible during inline ↔ fullscreen transitions.

Fix

Replace the fit-content width measurement with window.innerWidth. The height measurement (max-content) is preserved since hosts rely on it. Neither the iOS nor web host uses the width value from size-changed notifications — both only consume height — so this change has no functional impact on hosts.

Testing

  • Confirmed scroll position fix on iOS: scrollLeft dropped from 6406 to 772 when entering fullscreen before the fix; stays stable after
  • Applied equivalent CSS fix in Safari Web Inspector and verified scroll position preserved
  • All existing tests pass (88/88)

The setupSizeChangedNotifications method temporarily sets
html.style.width to 'fit-content' to measure intrinsic content width.
For responsive apps that derive width from their container (width: 100%,
flex: 1, etc.), fit-content resolves to 0px. The synchronous reflow at
0px causes browsers to clamp scrollLeft on all horizontal scroll
containers to 0, permanently destroying their scroll positions.

Replace the fit-content width measurement with window.innerWidth. The
height measurement (max-content) is preserved since hosts rely on it.
Neither the iOS nor web host uses the width value from size-changed
notifications, so this change has no functional impact on hosts while
fixing scroll position clamping for all MCP apps with horizontal scroll
views.
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 25, 2026

Open in StackBlitz

@modelcontextprotocol/ext-apps

npm i https://pkg.pr.new/@modelcontextprotocol/ext-apps@567

@modelcontextprotocol/server-basic-preact

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-preact@567

@modelcontextprotocol/server-basic-react

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-react@567

@modelcontextprotocol/server-basic-solid

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-solid@567

@modelcontextprotocol/server-basic-svelte

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-svelte@567

@modelcontextprotocol/server-basic-vanillajs

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-vanillajs@567

@modelcontextprotocol/server-basic-vue

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-vue@567

@modelcontextprotocol/server-budget-allocator

npm i https://pkg.pr.new/@modelcontextprotocol/server-budget-allocator@567

@modelcontextprotocol/server-cohort-heatmap

npm i https://pkg.pr.new/@modelcontextprotocol/server-cohort-heatmap@567

@modelcontextprotocol/server-customer-segmentation

npm i https://pkg.pr.new/@modelcontextprotocol/server-customer-segmentation@567

@modelcontextprotocol/server-debug

npm i https://pkg.pr.new/@modelcontextprotocol/server-debug@567

@modelcontextprotocol/server-map

npm i https://pkg.pr.new/@modelcontextprotocol/server-map@567

@modelcontextprotocol/server-pdf

npm i https://pkg.pr.new/@modelcontextprotocol/server-pdf@567

@modelcontextprotocol/server-scenario-modeler

npm i https://pkg.pr.new/@modelcontextprotocol/server-scenario-modeler@567

@modelcontextprotocol/server-shadertoy

npm i https://pkg.pr.new/@modelcontextprotocol/server-shadertoy@567

@modelcontextprotocol/server-sheet-music

npm i https://pkg.pr.new/@modelcontextprotocol/server-sheet-music@567

@modelcontextprotocol/server-system-monitor

npm i https://pkg.pr.new/@modelcontextprotocol/server-system-monitor@567

@modelcontextprotocol/server-threejs

npm i https://pkg.pr.new/@modelcontextprotocol/server-threejs@567

@modelcontextprotocol/server-transcript

npm i https://pkg.pr.new/@modelcontextprotocol/server-transcript@567

@modelcontextprotocol/server-video-resource

npm i https://pkg.pr.new/@modelcontextprotocol/server-video-resource@567

@modelcontextprotocol/server-wiki-explorer

npm i https://pkg.pr.new/@modelcontextprotocol/server-wiki-explorer@567

commit: 0d1e17c

Hosts determine the container size in fullscreen mode, so size-changed
notifications are not needed. The temporary max-content height override
used for measurement causes visible vertical jitter during animated
fullscreen transitions by briefly reflowing the document on every frame.
@mel-anthropic mel-anthropic marked this pull request as ready for review March 26, 2026 06:02
Copy link
Copy Markdown
Contributor

@ochafik ochafik left a comment

Choose a reason for hiding this comment

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

Thanks @mel-anthropic !

@ochafik ochafik merged commit a7273bb into modelcontextprotocol:main Mar 26, 2026
17 checks passed
ochafik added a commit that referenced this pull request Mar 26, 2026
Changes since 1.3.1:
- Fix auto-resize destroying horizontal scroll positions (#567)
- Remove examples/pdf-server/plugin/ — canonical copy is upcoming in knowledge-work-plugins (#565)
@ochafik ochafik mentioned this pull request Mar 26, 2026
2 tasks
mel-anthropic added a commit to mel-anthropic/ext-apps that referenced this pull request Mar 26, 2026
Reverts the fullscreen displayMode guard added in modelcontextprotocol#567. Skipping
size-changed measurement during fullscreen caused apps to not receive
an initial size report after the transition, breaking layout for some
apps.
ochafik pushed a commit that referenced this pull request Mar 26, 2026
Reverts the fullscreen displayMode guard added in #567. Skipping
size-changed measurement during fullscreen caused apps to not receive
an initial size report after the transition, breaking layout for some
apps.
ochafik added a commit that referenced this pull request Mar 27, 2026
Changes since 1.3.1:
- Revert fullscreen size-changed skip (#570)
- Fix auto-resize destroying horizontal scroll positions (#567)
- Remove examples/pdf-server/plugin/ — canonical copy is upcoming in knowledge-work-plugins (#565)
ochafik added a commit that referenced this pull request Mar 27, 2026
Changes since 1.3.1:
- Revert fullscreen size-changed skip (#570)
- Fix auto-resize destroying horizontal scroll positions (#567)
- Remove examples/pdf-server/plugin/ — canonical copy is upcoming in knowledge-work-plugins (#565)
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.

2 participants