#16020: perf(ui): virtualize chat message list for large conversations
app: web-ui
size: XS
## Summary
- Replace `repeat()` with `virtualize()` from `@lit-labs/virtualizer` in chat thread rendering
- Only visible messages (+ small buffer) are rendered in the DOM, keeping memory and render time constant regardless of history size
- Remove the previous 200-message render limit — virtualization handles unlimited messages efficiently
- Net -11 lines of code
## Why
The Control UI renders all messages as DOM nodes, which causes the browser tab to freeze or crash with long chat histories (~6 MB+ transcripts). Virtualization solves this at the rendering layer by only mounting elements in or near the viewport.
Prior art: PR #5743 attempted the same approach but went stale.
## Test plan
- [x] Build passes (`pnpm build`)
- [x] Lint clean
- [x] Tested with large conversation histories — smooth scrolling, no freezes
Ref #15992
lobster-biscuit
> 🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Replaces Lit's `repeat()` directive with `virtualize()` from `@lit-labs/virtualizer` in the chat thread, so only visible messages (plus a small buffer) are rendered in the DOM. This eliminates the previous 200-message hard cap and keeps rendering performance constant regardless of conversation length.
- **New dependency**: `@lit-labs/virtualizer@^2.1.1` added to `ui/package.json`; compatible with the existing `lit@^3.3.2`.
- **Render limit removed**: The `CHAT_HISTORY_RENDER_LIMIT = 200` constant and the "showing last N messages" system notice are deleted; virtualization handles unlimited messages efficiently.
- **Type fix**: A follow-up commit correctly changes the `renderItem` fallback from `nothing` to `` html`` `` since `virtualize()` expects a `TemplateResult`, not Lit's `nothing` symbol.
- **Scroll concern**: `virtualize({scroller: true})` takes over scroll management of `.chat-thread`, while `app-scroll.ts` (`scheduleChatScroll`) independently manipulates `scrollTop`/`scrollHeight` on the same element. With variable-height messages (markdown, images, tool cards), the virtualizer's estimated scroll height shifts as items are measured, which could cause the auto-scroll-to-bottom behavior to be unreliable. Worth validating with conversations containing very different message heights.
<h3>Confidence Score: 3/5</h3>
- Likely safe for most cases, but the dual scroll management between the virtualizer and existing auto-scroll logic needs targeted manual testing with variable-height messages.
- The core change (repeat → virtualize) is a well-motivated performance improvement with a clean implementation (-11 lines net). The type compatibility fix is correct. However, the interaction between the virtualizer's internal scroll management and the existing app-scroll.ts scroll-to-bottom logic has not been verified to work reliably with variable-height chat items, and could cause scroll jank or missed auto-scroll in edge cases.
- Pay close attention to `ui/src/ui/views/chat.ts` — specifically the interaction between `virtualize({scroller: true})` and the scroll management in `ui/src/ui/app-scroll.ts`.
<sub>Last reviewed commit: 86328cc</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#7522: fix(webchat): auto-scroll when message queue changes
by alsoknownasfoo · 2026-02-02
76.2%
#20347: fix(webchat): resolve streaming scroll race condition
by ndaemy · 2026-02-18
75.0%
#19754: feat(webchat): add cursor-based pagination to chat.history
by aleiby · 2026-02-18
73.5%
#15118: Fix webchat ghost bubble when model replies with NO_REPLY
by jwchmodx · 2026-02-13
73.2%
#14966: fix(webchat): preserve user message visibility after chat.send
by BenediktSchackenberg · 2026-02-12
72.8%
#22798: feat(webchat): ChatGPT-style multi-chat threads with generated titles
by opnsec · 2026-02-21
72.1%
#3721: fix(ui): webchat not displaying chat responses
by maxmaxrouge-rgb · 2026-01-29
71.9%
#16006: fix(gateway): reduce chat.history byte cap from 6 MB to 2 MB
by fagemx · 2026-02-14
71.7%
#15110: fix: enable auto-scroll during assistant response streaming
by jwchmodx · 2026-02-13
71.3%
#9195: Fix: Control UI fails to render new messages after chat.history Web...
by vishaltandale00 · 2026-02-05
70.2%