- Overview
- Anatomy
- Header
- Navigation
- Renderers
The Code Viewer renders code-like plain text, logs, and source-linked extraction text with stable line numbers. It loads a bounded text resource up front so every line can be addressed, then renders a virtualized fixed-height line window so large logs stay scrollable.
"use client";
import { CodeViewer } from "@/components/ui/code-viewer";
export function CodeViewerDemo() {
return (
<div className="h-[460px] min-h-0">
<CodeViewer
source={{
kind: "url",Installation
pnpm dlx shadcn@latest add @retab/code-viewer
Usage
import { CodeViewer } from "@/components/ui/code-viewer";
export function Example() {
return (
<CodeViewer
source={{
kind: "url",
url: "/samples/extraction-run.log",
fileName: "extraction-run.log",
}}
highlight={{ start: 12, end: 14 }}
/>
);
}Inline text is supported too:
<CodeViewer
source={{
kind: "text",
text: "first line\nsecond line",
fileName: "inline.log",
}}
/>Features
- Virtualized line rendering — only the visible line window plus overscan is mounted, so large logs do not create thousands of DOM nodes.
- Stable line addressing —
highlightandscrollToLineRangeuse 1-based inclusive line ranges. - Resource-based sources — URL, Blob, and inline text sources share the same bounded loading path.
- Local error states — failed URL loads can retry without tearing down the surrounding page.
- Zoom and download — the controls expose text scale controls and downloads from the source resource.
Languages
"use client";
import * as React from "react";
import { cn } from "@/lib/utils";
import { CodeViewer } from "@/components/ui/code-viewer";
import type { CodeLineRange } from "@/components/ui/code-viewer";
type Sample = {
id: string;Syntax highlighting is powered by Prism. A curated set of common languages ships by default — JSON, JavaScript / JSX, TypeScript / TSX, Python, YAML, Bash, SQL, Go, Rust, Java, Markdown, CSS, and HTML / XML — resolved from the source's file extension (falling back to its MIME type for inline sources without one). A file whose extension is not in the table renders as plain, unhighlighted text.
The viewer tokenizes each line independently so highlighting stays cheap even on very large files — a deliberate trade-off that means multi-line constructs (template literals, block comments, docstrings) are highlighted per line rather than across line boundaries.
To add another language, import its Prism component once — at your app entry
point or directly in code-viewer-syntax.ts (prismjs is already installed) —
and add a row mapping the file extension to the Prism language id:
// in code-viewer-syntax.ts
import "prismjs/components/prism-kotlin";
const LANGUAGE_BY_EXTENSION: Record<string, string> = {
// …languages that ship by default
kt: "kotlin",
};Token colors are CSS variables (--cv-token-keyword, --cv-token-string,
--cv-token-comment, …) with light and dark defaults, so a theme can override
any of them. A token kind a language emits that has no color rule simply
inherits the foreground color.
API Reference
| Prop | Type | Description |
|---|---|---|
source | CodeDocumentSource | Required source descriptor. Supports URL, Blob, and inline text resources. |
className | string | Optional class on the viewer container. |
controls | boolean | Show line count, zoom controls, and download action. Defaults to true. |
download | boolean | Show the download action in the controls. Defaults to true. |
highlight | CodeLineRange | null | 1-based inclusive line range to highlight. |
bare | boolean | Drop the outer border/background so the viewer fills its container. |
maxBytes | number | Maximum text payload size accepted by the viewer. |
maxLines | number | Maximum number of lines accepted by the viewer. |
Ref
import * as React from "react";
import { CodeViewer, type CodeViewerHandle } from "@/components/ui/code-viewer";
export function Example() {
const viewerRef = React.useRef<CodeViewerHandle>(null);
return (
<CodeViewer
ref={viewerRef}
source={{ kind: "text", text: "alpha\nbeta\ngamma" }}
highlight={{ start: 2, end: 2 }}
/>
);
}scrollToLineRange(range, options?) scrolls any normalized line range into
view, even when that line is outside the currently mounted virtual window.
getViewportElement() returns the scroll viewport element, or null before
mount — useful for scroll syncing and measurement.
Source
"use client";
import * as React from "react";
import type { ViewerResource } from "@/lib/viewer-resource";
import { CodeViewerFallback } from "./code-viewer-chrome";
import { CodeViewerContent } from "./code-viewer-content";
import type { CodeViewerHandle, CodeViewerProps } from "./code-viewer-types";
import { PlainTextViewerFrame } from "./plain-text-viewer-frame";
export type {