Skip to content

Scrolling back to the bottom does not restore anchored scroll #6677

Description

@CXRunfree

I'm using Textual 8.2.8. An anchored container (widget.anchor()) stops following new content after any scroll_to/scroll_relative/scroll_by call (or scrollbar drag). The only way to restore the anchor is landing exactly on the bottom edge, and since that edge keeps moving while content streams, the anchor effectively never re-engages.

Minimal repro

from textual.app import App, ComposeResult
from textual.containers import VerticalScroll
from textual.widgets import Static


class AnchorStuck(App):
    def compose(self) -> ComposeResult:
        with VerticalScroll(id="v"):
            for i in range(30):
                yield Static(f"line {i}")

    def on_mount(self) -> None:
        v = self.query_one("#v", VerticalScroll)
        v.anchor()
        self.set_interval(0.3, self.step)
        self._steps = 0

    def step(self) -> None:
        self._steps += 1
        v = self.query_one("#v", VerticalScroll)
        if self._steps == 1:
            v.scroll_relative(y=-1, animate=False)   # e.g. a wheel tick while streaming
        else:
            v.mount(Static(f"line {30 + self._steps}"))
            self.log(f"scroll_y={v.scroll_y} max={v.max_scroll_y}")

if __name__ == "__main__":
    AnchorStuck().run()

Expected:
while anchored, content growth keeps the viewport glued to the bottom until the user scrolls away.
Actual:
after the scroll_relative, the anchor is released; content keeps growing below the viewport, scroll_y stays frozen, and the new lines are off-screen.

Root cause

  • scroll_to/scroll_relative/scroll_by default to release_anchor=True (widget.py).
  • The compositor bottom-gluing branch requires _anchored and not _anchor_released (_compositor.py), so it is skipped whenever the anchor was released.
  • The only restore path is _check_anchor in watch_scroll_y, which requires scroll_y >= max_scroll_y (widget.py), practically unreachable while content keeps growing.

Related: #6652 (same compositor anchor branch, negative offset when content is shorter than the viewport).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions