How to build an accessible LogViewer in React
The scroll region is role="log" with aria-live="polite" so assistive tech announces new output without stealing focus; the container is keyboard-scrollable and a visually-hidden live status reports the line count; color is paired with level semantics, never the sole encoding
When to use a LogViewer
- Rendering continuous, high-volume log or stream output (build/deploy logs, server output)
- Showing thousands of lines without mounting a DOM node per line
- Auto-following live output while letting the user scroll back to inspect history
When not to use it
- A short, static block of code or output — use a <pre> or Code block
- Tabular data with columns — use DataTable
- A rich interactive terminal with cursor addressing — out of scope (line-oriented only)
Keyboard interactions
Role log, verified at WCAG 2.2-AA.
TabArrowUpArrowDownPageUpPageDown
Common mistakes
Avoid: logsSignal.value = [...logsSignal.value.slice(1), line]
Prefer: const logs = useStreamBuffer({ capacity: 1000 }); logs.append(line)
The slice pattern reallocates the whole array per line (O(n)) and renders per line; the stream buffer is O(1) and renders once per frame
Example
const logs = useStreamBuffer<LogLine>({ capacity: 1000 })
// socket.onmessage = (e) => logs.append({ id: seq++, text: e.data })
<LogViewer lines={logs.signal} />