Log Viewer

Scrollable log output component for displaying streaming logs or CLI-style output in web apps. Three variants — terminal, minimal, and filterable — cover most log display needs.

lucide-react

Preview

Application Logs40 lines
14:30:00.000INFStatic assets compiled in 1.2s
14:30:00.492INFHealth check passed
14:30:02.320VRBSocket keepalive ping
14:30:05.190INFConnected to database
14:30:02.360VRBSocket keepalive ping
14:30:03.730INFRequest completed in 42ms
14:30:07.008INFBackground job enqueued: email.send
14:30:01.792DBGJWT token expires in 3540s
14:30:14.600ERRECONNREFUSED: Could not connect to Redis at 127.0.0.1:6379
14:30:09.000WRNRate limit approaching for client 10.0.0.3
14:30:01.460INFServer listening on port 3000
14:30:18.381VRBEvent loop lag: 0.4ms
14:30:16.164ERRSSL handshake failed for upstream api.provider.com
14:30:08.242INFHealth check passed
14:30:11.578INFDeployment ready at https://app.example.com
14:30:06.225INFStatic assets compiled in 1.2s
14:30:07.760WRNDeprecated API endpoint called: /api/v1/users
14:30:20.264INFTLS certificate valid for 89 days
14:30:17.406INFTLS certificate valid for 89 days
14:30:22.553DBGRoute matched: GET /api/users/:id → UserController.show
14:30:29.360VRBEntering middleware: cors
14:30:33.474WRNRate limit approaching for client 10.0.0.3
14:30:37.664INFBackground job enqueued: email.send
14:30:08.441INFServer listening on port 3000
14:30:14.352DBGCache miss for key: session:abc123
14:30:07.675ERROut of memory: heap limit reached (1.5GB)
14:30:42.536VRBExiting middleware: cors (0.1ms)
14:30:52.110INFMiddleware chain resolved (3 handlers)
14:30:54.376WRNRate limit approaching for client 10.0.0.3
14:30:21.460WRNRequest timeout extended to 30s for /api/export
14:30:47.550DBGResponse serialized in 0.3ms
14:30:36.022ERRSSL handshake failed for upstream api.provider.com
14:30:23.104INFWorker process started (pid: 5821)
14:30:46.365WRNDisk usage above 90% on /var/log
14:30:34.408INFSession created for user admin@example.com
14:30:30.660INFMiddleware chain resolved (3 handlers)
14:30:12.600WRNRequest timeout extended to 30s for /api/export
14:30:34.077WRNDeprecated API endpoint called: /api/v1/users
14:30:57.760INFHealth check passed
14:30:41.145VRBEntering middleware: cors

Installation

$ shadcn add https://ui.justinlevine.me/r/log-viewer.json

Usage

import { LogViewerTerminal, LogViewerMinimal, LogViewerFilterable } from "@/components/log-viewer"
<LogViewerTerminal entries={logs} title="Server Logs" />

Pass an array of { level, message, timestamp? } entries. All three variants support auto-scrolling and accept the same LogEntry format.

Playground

Switch between variants and click Start streaming to see auto-scroll in action.

Application Logs12 lines
14:30:00.000INFServer listening on port 3000
14:30:01.453WRNConnection pool nearing capacity (48/50)
14:30:01.200DBGRoute matched: GET /api/users/:id → UserController.show
14:30:02.832ERRDatabase migration 0042_add_index failed: relation already exists
14:30:02.740INFHealth check passed
14:30:08.120WRNRate limit approaching for client 10.0.0.3
14:30:04.572VRBGC pause: 2.1ms
14:30:02.282VRBExiting middleware: cors (0.1ms)
14:30:02.472DBGRoute matched: GET /api/users/:id → UserController.show
14:30:08.415DBGRoute matched: GET /api/users/:id → UserController.show
14:30:20.650INFSession created for user admin@example.com
14:30:11.990DBGResponse serialized in 0.3ms

Variants

Terminal

Full CLI-style interface with toolbar, line numbers, timestamps, search, copy, export, and pause/resume.

Default terminal

Server Logs40 lines
14:30:00.000INFStatic assets compiled in 1.2s
14:30:00.492INFHealth check passed
14:30:02.320VRBSocket keepalive ping
14:30:05.190INFConnected to database
14:30:02.360VRBSocket keepalive ping
14:30:03.730INFRequest completed in 42ms
14:30:07.008INFBackground job enqueued: email.send
14:30:01.792DBGJWT token expires in 3540s
14:30:14.600ERRECONNREFUSED: Could not connect to Redis at 127.0.0.1:6379
14:30:09.000WRNRate limit approaching for client 10.0.0.3
14:30:01.460INFServer listening on port 3000
14:30:18.381VRBEvent loop lag: 0.4ms
14:30:16.164ERRSSL handshake failed for upstream api.provider.com
14:30:08.242INFHealth check passed
14:30:11.578INFDeployment ready at https://app.example.com
14:30:06.225INFStatic assets compiled in 1.2s
14:30:07.760WRNDeprecated API endpoint called: /api/v1/users
14:30:20.264INFTLS certificate valid for 89 days
14:30:17.406INFTLS certificate valid for 89 days
14:30:22.553DBGRoute matched: GET /api/users/:id → UserController.show
14:30:29.360VRBEntering middleware: cors
14:30:33.474WRNRate limit approaching for client 10.0.0.3
14:30:37.664INFBackground job enqueued: email.send
14:30:08.441INFServer listening on port 3000
14:30:14.352DBGCache miss for key: session:abc123
14:30:07.675ERROut of memory: heap limit reached (1.5GB)
14:30:42.536VRBExiting middleware: cors (0.1ms)
14:30:52.110INFMiddleware chain resolved (3 handlers)
14:30:54.376WRNRate limit approaching for client 10.0.0.3
14:30:21.460WRNRequest timeout extended to 30s for /api/export
14:30:47.550DBGResponse serialized in 0.3ms
14:30:36.022ERRSSL handshake failed for upstream api.provider.com
14:30:23.104INFWorker process started (pid: 5821)
14:30:46.365WRNDisk usage above 90% on /var/log
14:30:34.408INFSession created for user admin@example.com
14:30:30.660INFMiddleware chain resolved (3 handlers)
14:30:12.600WRNRequest timeout extended to 30s for /api/export
14:30:34.077WRNDeprecated API endpoint called: /api/v1/users
14:30:57.760INFHealth check passed
14:30:41.145VRBEntering middleware: cors

No line numbers, no timestamps

Compact40 lines
INFStatic assets compiled in 1.2s
INFHealth check passed
VRBSocket keepalive ping
INFConnected to database
VRBSocket keepalive ping
INFRequest completed in 42ms
INFBackground job enqueued: email.send
DBGJWT token expires in 3540s
ERRECONNREFUSED: Could not connect to Redis at 127.0.0.1:6379
WRNRate limit approaching for client 10.0.0.3
INFServer listening on port 3000
VRBEvent loop lag: 0.4ms
ERRSSL handshake failed for upstream api.provider.com
INFHealth check passed
INFDeployment ready at https://app.example.com
INFStatic assets compiled in 1.2s
WRNDeprecated API endpoint called: /api/v1/users
INFTLS certificate valid for 89 days
INFTLS certificate valid for 89 days
DBGRoute matched: GET /api/users/:id → UserController.show
VRBEntering middleware: cors
WRNRate limit approaching for client 10.0.0.3
INFBackground job enqueued: email.send
INFServer listening on port 3000
DBGCache miss for key: session:abc123
ERROut of memory: heap limit reached (1.5GB)
VRBExiting middleware: cors (0.1ms)
INFMiddleware chain resolved (3 handlers)
WRNRate limit approaching for client 10.0.0.3
WRNRequest timeout extended to 30s for /api/export
DBGResponse serialized in 0.3ms
ERRSSL handshake failed for upstream api.provider.com
INFWorker process started (pid: 5821)
WRNDisk usage above 90% on /var/log
INFSession created for user admin@example.com
INFMiddleware chain resolved (3 handlers)
WRNRequest timeout extended to 30s for /api/export
WRNDeprecated API endpoint called: /api/v1/users
INFHealth check passed
VRBEntering middleware: cors

Minimal

Simple scrolling log lines with colored dots. Ideal for compact panels, sidebars, or embedded contexts.

Minimal with timestamps

14:30:00Server listening on port 3000
14:30:01Connection pool nearing capacity (48/50)
14:30:01Route matched: GET /api/users/:id → UserController.show
14:30:02Database migration 0042_add_index failed: relation already exists
14:30:02Health check passed
14:30:08Rate limit approaching for client 10.0.0.3
14:30:04GC pause: 2.1ms
14:30:02Exiting middleware: cors (0.1ms)
14:30:02Route matched: GET /api/users/:id → UserController.show
14:30:08Route matched: GET /api/users/:id → UserController.show
14:30:20Session created for user admin@example.com
14:30:11Response serialized in 0.3ms

Minimal without timestamps

Server listening on port 3000
Connection pool nearing capacity (48/50)
Route matched: GET /api/users/:id → UserController.show
Database migration 0042_add_index failed: relation already exists
Health check passed
Rate limit approaching for client 10.0.0.3
GC pause: 2.1ms
Exiting middleware: cors (0.1ms)
Route matched: GET /api/users/:id → UserController.show
Route matched: GET /api/users/:id → UserController.show
Session created for user admin@example.com
Response serialized in 0.3ms

Filterable

Adds level filter toggles with live counts and inline search. Toggle levels on/off to focus on errors or warnings.

Filterable with all levels

All Levels40 / 40
14:30:00INFStatic assets compiled in 1.2s
14:30:00INFHealth check passed
14:30:02VRBSocket keepalive ping
14:30:05INFConnected to database
14:30:02VRBSocket keepalive ping
14:30:03INFRequest completed in 42ms
14:30:07INFBackground job enqueued: email.send
14:30:01DBGJWT token expires in 3540s
14:30:14ERRECONNREFUSED: Could not connect to Redis at 127.0.0.1:6379
14:30:09WRNRate limit approaching for client 10.0.0.3
14:30:01INFServer listening on port 3000
14:30:18VRBEvent loop lag: 0.4ms
14:30:16ERRSSL handshake failed for upstream api.provider.com
14:30:08INFHealth check passed
14:30:11INFDeployment ready at https://app.example.com
14:30:06INFStatic assets compiled in 1.2s
14:30:07WRNDeprecated API endpoint called: /api/v1/users
14:30:20INFTLS certificate valid for 89 days
14:30:17INFTLS certificate valid for 89 days
14:30:22DBGRoute matched: GET /api/users/:id → UserController.show
14:30:29VRBEntering middleware: cors
14:30:33WRNRate limit approaching for client 10.0.0.3
14:30:37INFBackground job enqueued: email.send
14:30:08INFServer listening on port 3000
14:30:14DBGCache miss for key: session:abc123
14:30:07ERROut of memory: heap limit reached (1.5GB)
14:30:42VRBExiting middleware: cors (0.1ms)
14:30:52INFMiddleware chain resolved (3 handlers)
14:30:54WRNRate limit approaching for client 10.0.0.3
14:30:21WRNRequest timeout extended to 30s for /api/export
14:30:47DBGResponse serialized in 0.3ms
14:30:36ERRSSL handshake failed for upstream api.provider.com
14:30:23INFWorker process started (pid: 5821)
14:30:46WRNDisk usage above 90% on /var/log
14:30:34INFSession created for user admin@example.com
14:30:30INFMiddleware chain resolved (3 handlers)
14:30:12WRNRequest timeout extended to 30s for /api/export
14:30:34WRNDeprecated API endpoint called: /api/v1/users
14:30:57INFHealth check passed
14:30:41VRBEntering middleware: cors

Custom colors

Pass a colorScale to override colors per level. Only specify the levels you want to change — the rest fall back to defaults.

Ocean

Ocean34 / 40
14:30:00INFStatic assets compiled in 1.2s
14:30:00INFHealth check passed
14:30:05INFConnected to database
14:30:03INFRequest completed in 42ms
14:30:07INFBackground job enqueued: email.send
14:30:01DBGJWT token expires in 3540s
14:30:14ERRECONNREFUSED: Could not connect to Redis at 127.0.0.1:6379
14:30:09WRNRate limit approaching for client 10.0.0.3
14:30:01INFServer listening on port 3000
14:30:16ERRSSL handshake failed for upstream api.provider.com
14:30:08INFHealth check passed
14:30:11INFDeployment ready at https://app.example.com
14:30:06INFStatic assets compiled in 1.2s
14:30:07WRNDeprecated API endpoint called: /api/v1/users
14:30:20INFTLS certificate valid for 89 days
14:30:17INFTLS certificate valid for 89 days
14:30:22DBGRoute matched: GET /api/users/:id → UserController.show
14:30:33WRNRate limit approaching for client 10.0.0.3
14:30:37INFBackground job enqueued: email.send
14:30:08INFServer listening on port 3000
14:30:14DBGCache miss for key: session:abc123
14:30:07ERROut of memory: heap limit reached (1.5GB)
14:30:52INFMiddleware chain resolved (3 handlers)
14:30:54WRNRate limit approaching for client 10.0.0.3
14:30:21WRNRequest timeout extended to 30s for /api/export
14:30:47DBGResponse serialized in 0.3ms
14:30:36ERRSSL handshake failed for upstream api.provider.com
14:30:23INFWorker process started (pid: 5821)
14:30:46WRNDisk usage above 90% on /var/log
14:30:34INFSession created for user admin@example.com
14:30:30INFMiddleware chain resolved (3 handlers)
14:30:12WRNRequest timeout extended to 30s for /api/export
14:30:34WRNDeprecated API endpoint called: /api/v1/users
14:30:57INFHealth check passed

Warm

Warm40 lines
14:30:00.000INFStatic assets compiled in 1.2s
14:30:00.492INFHealth check passed
14:30:02.320VRBSocket keepalive ping
14:30:05.190INFConnected to database
14:30:02.360VRBSocket keepalive ping
14:30:03.730INFRequest completed in 42ms
14:30:07.008INFBackground job enqueued: email.send
14:30:01.792DBGJWT token expires in 3540s
14:30:14.600ERRECONNREFUSED: Could not connect to Redis at 127.0.0.1:6379
14:30:09.000WRNRate limit approaching for client 10.0.0.3
14:30:01.460INFServer listening on port 3000
14:30:18.381VRBEvent loop lag: 0.4ms
14:30:16.164ERRSSL handshake failed for upstream api.provider.com
14:30:08.242INFHealth check passed
14:30:11.578INFDeployment ready at https://app.example.com
14:30:06.225INFStatic assets compiled in 1.2s
14:30:07.760WRNDeprecated API endpoint called: /api/v1/users
14:30:20.264INFTLS certificate valid for 89 days
14:30:17.406INFTLS certificate valid for 89 days
14:30:22.553DBGRoute matched: GET /api/users/:id → UserController.show
14:30:29.360VRBEntering middleware: cors
14:30:33.474WRNRate limit approaching for client 10.0.0.3
14:30:37.664INFBackground job enqueued: email.send
14:30:08.441INFServer listening on port 3000
14:30:14.352DBGCache miss for key: session:abc123
14:30:07.675ERROut of memory: heap limit reached (1.5GB)
14:30:42.536VRBExiting middleware: cors (0.1ms)
14:30:52.110INFMiddleware chain resolved (3 handlers)
14:30:54.376WRNRate limit approaching for client 10.0.0.3
14:30:21.460WRNRequest timeout extended to 30s for /api/export
14:30:47.550DBGResponse serialized in 0.3ms
14:30:36.022ERRSSL handshake failed for upstream api.provider.com
14:30:23.104INFWorker process started (pid: 5821)
14:30:46.365WRNDisk usage above 90% on /var/log
14:30:34.408INFSession created for user admin@example.com
14:30:30.660INFMiddleware chain resolved (3 handlers)
14:30:12.600WRNRequest timeout extended to 30s for /api/export
14:30:34.077WRNDeprecated API endpoint called: /api/v1/users
14:30:57.760INFHealth check passed
14:30:41.145VRBEntering middleware: cors

Real-world example

A realistic CI/CD deploy log using the terminal variant.

Deploy pipeline

Deploy — main (abc1234)21 lines
14:00:00.000INFBuild triggered by push to main (abc1234)
14:00:00.500DBGCloning repository…
14:00:02.100DBGInstalling dependencies (pnpm install)…
14:00:10.400INFDependencies installed in 8.3s
14:00:10.500DBGRunning linter…
14:00:14.200INFLint passed (0 warnings, 0 errors)
14:00:14.300DBGRunning type checker…
14:00:18.100WRNType warning: unused variable 'tempData' in utils.ts:42
14:00:18.200INFType check completed with 1 warning
14:00:18.300DBGBuilding application (next build)…
14:00:30.700INFCompiled 142 modules in 12.4s
14:00:31.200INFGenerated 23 static pages
14:00:31.500INFBundle size: 245 KB (gzipped)
14:00:31.600DBGUploading build artifacts…
14:00:35.100INFArtifacts uploaded (3.2 MB)
14:00:35.200DBGProvisioning edge functions…
14:00:38.800INF3 edge functions deployed to 12 regions
14:00:39.000DBGRunning health checks…
14:00:41.500INFHealth check passed (all regions responding)
14:00:43.000INFDNS propagation complete
14:00:43.200INF✓ Deployment successful — https://app.example.com

API Reference

LogEntry

PropType

LogViewerTerminal

PropType

LogViewerMinimal

PropType

LogViewerFilterable

PropType

LevelColors

PropType

Notes

  • Client component. Uses "use client" for scroll tracking, search state, and clipboard access.
  • Auto-scroll. New entries scroll into view when the user is at the bottom. Scrolling up pauses auto-scroll and shows a "New logs below" button. The terminal variant also has an explicit pause/resume toggle.
  • Five log levels. Each level (error, warn, info, debug, verbose) has distinct colors that work in both light and dark modes.
  • Export. The terminal and filterable variants include a download button that exports logs as a plain text file with timestamps and level labels.
  • Search highlighting. Search matches are highlighted inline. In the filterable variant, search and level filters compose — only entries matching both are shown.
  • Accessibility. The log container uses role="log" and aria-live="polite" so screen readers announce new entries. Filter toggles use role="checkbox" with aria-checked.
  • No dependencies. Only requires React, Tailwind, lucide-react, and the cn utility. No virtual-scrolling library — suitable for log sets up to a few thousand entries.