Introducing shieldcn — README badges, shadcn style.

Check it out

Log Viewer

Scrollable log output component for displaying streaming logs or CLI-style output in web apps.

lucide-react
Loading...

Installation

$ shadcn add @jalco/log-viewer

Usage

import { LogViewerTerminal } from "@/components/log-viewer"
<LogViewerTerminal />

Variants

Terminal

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

Terminal viewer

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

Filterable

Includes log-level toggle filters in the toolbar to quickly show/hide specific severities.

Filterable viewer

Filterable Logs34 / 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

Minimal

Lightweight, read-only variant without toolbars or controls. Just a scrollable log area.

Minimal viewer

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

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.
  • Icon library. Uses Lucide icons by default. Since this is copy-paste code, you can swap the imports if your project uses a different icon library.