Skip to content

fix(cli): ensure dialogs stay scrolled to bottom in alternate buffer mode#20527

Merged
jacob314 merged 2 commits intomainfrom
resize_observer2
Feb 27, 2026
Merged

fix(cli): ensure dialogs stay scrolled to bottom in alternate buffer mode#20527
jacob314 merged 2 commits intomainfrom
resize_observer2

Conversation

@jacob314
Copy link
Contributor

@jacob314 jacob314 commented Feb 27, 2026

Summary

Fix behavior so scroll to bottom is robust and optimize ScrollableList positions using ResizeObserver.

  • Improved Scroll-to-Bottom Behavior: The core scrolling components (Scrollable and VirtualizedList) have been updated to more reliably maintain a 'scrolled to bottom' state, especially when content dynamically changes or resizes. This addresses issues where dialogs might not stay at the bottom in alternate buffer mode.
  • Dynamic Sizing with ResizeObserver: Introduced ResizeObserver in Scrollable and VirtualizedList to accurately detect changes in content and container dimensions. This replaces previous manual measurement methods, leading to more responsive and accurate scroll calculations.
  • Enhanced Scroll Logic: The scroll calculation and state management have been refined across Scrollable and VirtualizedList to use Number.MAX_SAFE_INTEGER as a robust indicator for 'scroll to end', ensuring consistent behavior when new items are added or existing items change size.
  • Comprehensive Regression Tests: New and updated tests have been added for Scrollable, ScrollableList, and VirtualizedList to cover various dynamic content scenarios, including item additions, removals, and resizing, ensuring the improved scroll-to-bottom functionality is stable.

Demo of fixed behavior:
https://screencast.googleplex.com/cast/NTYwNTk4NTIxNjM2NDU0NHw3YmRjOTIwYi03OQ

Fixes #18700

Details: switch to using ResizeObserver instead of using useLayoutEffect for size measurement as using useLayoutEffect would miss when components resized. ResizeObserver was recently added to the ink for and behaves like ResizeObserver on the web.

@jacob314 jacob314 requested a review from a team as a code owner February 27, 2026 02:52
@gemini-cli
Copy link
Contributor

gemini-cli bot commented Feb 27, 2026

Hi @jacob314, thank you so much for your contribution to Gemini CLI! We really appreciate the time and effort you've put into this.

We're making some updates to our contribution process to improve how we track and review changes. Please take a moment to review our recent discussion post: Improving Our Contribution Process & Introducing New Guidelines.

Key Update: Starting January 26, 2026, the Gemini CLI project will require all pull requests to be associated with an existing issue. Any pull requests not linked to an issue by that date will be automatically closed.

Thank you for your understanding and for being a part of our community!

@github-actions
Copy link

You already have 7 pull requests open. Please work on getting existing PRs merged before opening more.

@github-actions github-actions bot closed this Feb 27, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the scrolling experience in CLI dialogs by ensuring that content consistently remains scrolled to the bottom when new information appears or existing content changes size. This is achieved through the adoption of ResizeObserver for dynamic dimension tracking and a more robust implementation of 'scroll to end' logic, leading to a smoother and more predictable user interface.

Highlights

  • Improved Scroll-to-Bottom Behavior: The core scrolling components (Scrollable and VirtualizedList) have been updated to more reliably maintain a 'scrolled to bottom' state, especially when content dynamically changes or resizes. This addresses issues where dialogs might not stay at the bottom in alternate buffer mode.
  • Dynamic Sizing with ResizeObserver: Introduced ResizeObserver in Scrollable and VirtualizedList to accurately detect changes in content and container dimensions. This replaces previous manual measurement methods, leading to more responsive and accurate scroll calculations.
  • Enhanced Scroll Logic: The scroll calculation and state management have been refined across Scrollable and VirtualizedList to use Number.MAX_SAFE_INTEGER as a robust indicator for 'scroll to end', ensuring consistent behavior when new items are added or existing items change size.
  • Comprehensive Regression Tests: New and updated tests have been added for Scrollable, ScrollableList, and VirtualizedList to cover various dynamic content scenarios, including item additions, removals, and resizing, ensuring the improved scroll-to-bottom functionality is stable.
Changelog
  • packages/cli/src/ui/components/shared/Scrollable.test.tsx
    • Updated tests to use waitFor for asynchronous assertions.
    • Removed ink mock for getInnerHeight and getScrollHeight.
    • Adjusted content rendering within tests to use Box for better control over height.
  • packages/cli/src/ui/components/shared/Scrollable.tsx
    • Replaced getInnerHeight and getScrollHeight with ResizeObserver for dynamic content and viewport sizing.
    • Refactored scroll logic to use viewportRefCallback and contentRefCallback for observing size changes.
    • Adjusted scrollBy and getScrollState to handle Number.MAX_SAFE_INTEGER for 'scroll to bottom' behavior.
    • Removed useLayoutEffect for size measurement, relying on ResizeObserver callbacks instead.
  • packages/cli/src/ui/components/shared/ScrollableList.test.tsx
    • Added new regression tests to validate scroll-to-bottom behavior when list items are added, removed, or resized dynamically.
    • Included tests for scenarios like removing the last item and adding new ones, and an item changing size without a full list re-render.
    • Added a test for prepending items and ensuring correct total height and scroll position.
  • packages/cli/src/ui/components/shared/ScrollableList.tsx
    • Modified scroll-to-end logic to correctly interpret targetScrollTop values at or beyond maxScrollTop as a request to scroll to the absolute end.
    • Updated scrollTo and animated scroll functions to use Number.MAX_SAFE_INTEGER for 'scroll to end' targets.
    • Adjusted scrollTop calculation in keypress handling to use actualScrollTop for more accurate boundary checks.
  • packages/cli/src/ui/components/shared/VirtualizedList.test.tsx
    • Integrated waitFor utility into existing tests to improve reliability of asynchronous rendering assertions.
  • packages/cli/src/ui/components/shared/VirtualizedList.tsx
    • Implemented ResizeObserver to precisely track container and individual item dimensions.
    • Replaced the heights array with a Record<string, number> for key-based height tracking, improving stability with dynamic lists.
    • Refined 'sticking to bottom' logic using actualScrollTop and Number.MAX_SAFE_INTEGER for more robust behavior.
    • Updated scrollBy, scrollTo, and scrollToEnd methods to leverage the new scroll-to-end logic.
    • Modified item rendering within Box components to include flexDirection="column" and flexShrink={0} for consistent layout.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a significant and well-executed refactoring of the Scrollable and VirtualizedList components to improve scrolling behavior, particularly the 'stick to bottom' functionality. The transition from useLayoutEffect with measureElement to using ResizeObserver is a major improvement for performance and reliability. The new regression tests are also excellent and cover important edge cases. I have one suggestion to remove a piece of redundant logic that could introduce subtle bugs.

Comment on lines +245 to 247
if (wasAtBottom && actualScrollTop >= prevScrollTop.current) {
setIsStickingToBottom(true);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

high

This logic for initiating the "sticking" behavior appears to be redundant and potentially incorrect. The wasAtBottom variable is calculated based on the state from the previous render, which means this condition won't trigger when a user scrolls to the bottom for the first time. The imperative scroll methods (scrollBy, scrollTo, scrollToEnd) already correctly handle setting isStickingToBottom when a scroll action reaches the end of the list. This block can be safely removed to avoid redundancy and prevent this latent bug.

@gemini-cli gemini-cli bot reopened this Feb 27, 2026
@gemini-cli
Copy link
Contributor

gemini-cli bot commented Feb 27, 2026

Thank you for linking an issue! This pull request has been automatically reopened.

@github-actions
Copy link

github-actions bot commented Feb 27, 2026

Size Change: +3.89 kB (+0.02%)

Total Size: 25.7 MB

Filename Size Change
./bundle/gemini.js 25.2 MB +3.89 kB (+0.02%)
ℹ️ View Unchanged
Filename Size
./bundle/node_modules/@google/gemini-cli-devtools/dist/client/main.js 221 kB
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/_client-assets.js 227 kB
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/index.js 11.5 kB
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/types.js 132 B
./bundle/sandbox-macos-permissive-open.sb 890 B
./bundle/sandbox-macos-permissive-proxied.sb 1.31 kB
./bundle/sandbox-macos-restrictive-open.sb 3.36 kB
./bundle/sandbox-macos-restrictive-proxied.sb 3.56 kB
./bundle/sandbox-macos-strict-open.sb 4.82 kB
./bundle/sandbox-macos-strict-proxied.sb 5.02 kB

compressed-size-action

@jacob314 jacob314 enabled auto-merge February 27, 2026 03:10
@gemini-cli gemini-cli bot added area/core Issues related to User Interface, OS Support, Core Functionality area/agent Issues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality 🔒 maintainer only ⛔ Do not contribute. Internal roadmap item. labels Feb 27, 2026
Copy link
Contributor

@jerop jerop left a comment

Choose a reason for hiding this comment

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

tested and works well, thanks!

@jacob314 jacob314 added this pull request to the merge queue Feb 27, 2026
Merged via the queue into main with commit 14dd07b Feb 27, 2026
28 checks passed
@jacob314 jacob314 deleted the resize_observer2 branch February 27, 2026 16:12
@jerop jerop added the release/patch-to-preview PR needs to be patch to preview release label Feb 27, 2026
BryanBradfo pushed a commit to BryanBradfo/gemini-cli that referenced this pull request Mar 5, 2026
@jerop jerop removed the release/patch-to-preview PR needs to be patch to preview release label Mar 9, 2026
liamhelmer pushed a commit to badal-io/gemini-cli that referenced this pull request Mar 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/agent Issues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality area/core Issues related to User Interface, OS Support, Core Functionality 🔒 maintainer only ⛔ Do not contribute. Internal roadmap item.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[UI] AskUser and ExitPlanMode dialogs should scroll to bottom in alternate buffer mode

2 participants