[GH-ISSUE #812] Mouse scroll events lost in bottom portion of terminal after shrinking window #991

Open
opened 2026-03-14 09:12:25 +03:00 by kerem · 0 comments
Owner

Originally created by @sbbae0318 on GitHub (Mar 14, 2026).
Original GitHub issue: https://github.com/anomalyco/opentui/issues/812

Bug

When a terminal is resized from a wider layout to a narrower (but taller) one, mouse wheel scroll events stop working for any row beyond the original terminal height. Scrolling in the upper portion of the screen still works. The split is deterministic based on the Y coordinate of the mouse cursor.

For example: start at 160x50, resize to 60x100. Scroll events at rows 0-49 work fine. Scroll events at rows 50-99 are silently dropped.

If the application is started in the narrow terminal from the beginning (no resize), scrolling works everywhere as expected.

Root cause

In packages/core/src/zig/renderer.zig, the resize function only updates hitGridWidth and hitGridHeight when the new grid needs a larger backing buffer:

const newHitGridSize = width * height;
const currentHitGridSize = self.hitGridWidth * self.hitGridHeight;
if (newHitGridSize > currentHitGridSize) {
    // ... reallocate ...
    self.hitGridWidth = width;   // only set here
    self.hitGridHeight = height; // only set here
}

When the total cell count shrinks (e.g. 16050=8000 -> 60100=6000), the condition is false, so hitGridWidth/hitGridHeight keep their old values. checkHit then rejects any coordinate beyond the stale bounds:

pub fn checkHit(self: *CliRenderer, x: u32, y: u32) u32 {
    if (x >= self.hitGridWidth or y >= self.hitGridHeight) {
        return 0;  // no target found
    }
    // ...
}

With no hit target, the scroll event in renderer.ts falls back to the focused renderable (typically the input prompt, not the scrollbox), so scroll doesn't happen.

Reproduction

  1. Start any opentui app with a scrollbox in a wide terminal (e.g. 160 columns)
  2. Shrink the terminal horizontally so it becomes narrower but taller (e.g. 60x100)
  3. Place mouse cursor in the bottom half of the screen and scroll -- nothing happens
  4. Move mouse cursor to the top half -- scrolling works
  5. Restart the app in the already-narrow terminal -- scrolling works everywhere

Confirmed with OpenCode over Windows Terminal -> SSH -> tmux.

Environment

  • opentui v0.1.87 (via OpenCode)
  • macOS (remote) + Windows Terminal (local)
  • tmux 3.5

Fix

PR coming -- move hitGridWidth/hitGridHeight assignment out of the if block so dimensions are always updated. The backing buffer is already large enough (it was allocated for the bigger size), so this is safe.

Originally created by @sbbae0318 on GitHub (Mar 14, 2026). Original GitHub issue: https://github.com/anomalyco/opentui/issues/812 ## Bug When a terminal is resized from a wider layout to a narrower (but taller) one, mouse wheel scroll events stop working for any row beyond the original terminal height. Scrolling in the upper portion of the screen still works. The split is deterministic based on the Y coordinate of the mouse cursor. For example: start at 160x50, resize to 60x100. Scroll events at rows 0-49 work fine. Scroll events at rows 50-99 are silently dropped. If the application is started in the narrow terminal from the beginning (no resize), scrolling works everywhere as expected. ## Root cause In `packages/core/src/zig/renderer.zig`, the `resize` function only updates `hitGridWidth` and `hitGridHeight` when the new grid needs a larger backing buffer: ```zig const newHitGridSize = width * height; const currentHitGridSize = self.hitGridWidth * self.hitGridHeight; if (newHitGridSize > currentHitGridSize) { // ... reallocate ... self.hitGridWidth = width; // only set here self.hitGridHeight = height; // only set here } ``` When the total cell count shrinks (e.g. 160*50=8000 -> 60*100=6000), the condition is false, so `hitGridWidth`/`hitGridHeight` keep their old values. `checkHit` then rejects any coordinate beyond the stale bounds: ```zig pub fn checkHit(self: *CliRenderer, x: u32, y: u32) u32 { if (x >= self.hitGridWidth or y >= self.hitGridHeight) { return 0; // no target found } // ... } ``` With no hit target, the scroll event in `renderer.ts` falls back to the focused renderable (typically the input prompt, not the scrollbox), so scroll doesn't happen. ## Reproduction 1. Start any opentui app with a scrollbox in a wide terminal (e.g. 160 columns) 2. Shrink the terminal horizontally so it becomes narrower but taller (e.g. 60x100) 3. Place mouse cursor in the bottom half of the screen and scroll -- nothing happens 4. Move mouse cursor to the top half -- scrolling works 5. Restart the app in the already-narrow terminal -- scrolling works everywhere Confirmed with OpenCode over Windows Terminal -> SSH -> tmux. ## Environment - opentui v0.1.87 (via OpenCode) - macOS (remote) + Windows Terminal (local) - tmux 3.5 ## Fix PR coming -- move `hitGridWidth`/`hitGridHeight` assignment out of the `if` block so dimensions are always updated. The backing buffer is already large enough (it was allocated for the bigger size), so this is safe.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/opentui#991
No description provided.