#6699·textual

RichLog horizontal scrollbar never shrinks when max_lines is set (Ghost Scrollbar)

Author: ToshalzambareCreated Aug 14, 2026Updated Sep 15, 2026

The bug

Bug Description: When writing to a RichLog with max_lines enabled, the widget tracks the horizontal width of the widest line to set the horizontal scrollbar. However, if the widest line falls out of the buffer and is trimmed to save memory, _widest_line_width is never recalculated.

This results in a permanently massive horizontal scrollbar that lets the user scroll into empty space, because it remembers the width of a line that no longer exists.

(Note: The original developer actually left a # TODO on line 270 of _rich_log.py acknowledging this exact flaw).

Working Example:

python
import asyncio
from textual.app import App, ComposeResult
from textual.widgets import RichLog

class RichLogTest(App):
    def compose(self) -> ComposeResult:
        # Set max_lines to 2 to easily trigger the buffer trim
        yield RichLog(max_lines=2)

async def test_rich_log():
    app = RichLogTest()
    async with app.run_test() as pilot:
        log = app.query_one(RichLog)
        
        # Write a long line
        log.write("A" * 100)
        await pilot.pause()
        assert log._widest_line_width == 100
        
        # Write two short lines, pushing the long line out of the max_lines buffer
        log.write("B" * 10)
        log.write("C" * 15)
        await pilot.pause()
        
        # BUG: The widest line in the buffer is now 15 chars, but the widget still remembers 100
        print(f"Current max width is: {log._widest_line_width} (Should be 15)")

if __name__ == "__main__":
    asyncio.run(test_rich_log())