Virtual Scrolling
The Logs tab uses virtual scrolling (windowing) to render only the rows currently visible in the viewport. This allows the tab to display thousands of log entries without DOM bloat or jank, even during rapid log streaming.
Why Virtualization Is Needed
Without virtualization, a log buffer of 10,000 entries would create 10,000 DOM nodes. Rendering and updating 10,000 nodes causes significant scroll lag and React reconciliation cost. With virtualization, the DOM contains at most ~30–50 rows at any time regardless of the buffer size.
How It Works
The Logs tab uses react-window (FixedSizeList) for virtualization. Each row has a fixed height (32px) so the total scrollable height can be computed without rendering all rows:
import { FixedSizeList } from 'react-window';
<FixedSizeList
height={panelContentHeight} // available height in the panel
itemCount={visibleLogs.length} // filtered log count
itemSize={32} // pixels per row
width="100%"
overscanCount={5} // render 5 extra rows above/below viewport
>
{({ index, style }) => (
<LogRow
log={visibleLogs[index]}
style={style} // absolute position set by react-window
searchTerm={searchTerm}
onExpand={handleExpand}
/>
)}
</FixedSizeList>
Auto-Scroll to Bottom
While the execution is running, the list auto-scrolls to the bottom as new entries arrive — similar to a terminal. If the user scrolls up to read earlier entries, auto-scroll pauses. It resumes when the user scrolls back to within 50px of the bottom:
const isAtBottom = scrollOffset >= (totalHeight - viewportHeight - 50);
useEffect(() => {
if (isAtBottom && isRunning) {
listRef.current?.scrollToItem(visibleLogs.length - 1, 'end');
}
}, [visibleLogs.length, isAtBottom, isRunning]);
Performance Numbers
| Metric | Value |
|---|---|
| Row height | 32px (fixed) |
| Rendered DOM rows | ~30–50 (visible + overscan) |
| Max buffer size | 10,000 entries |
| Auto-scroll resume threshold | 50px from bottom |
| Overscan rows | 5 above + 5 below viewport |