Marble UI
← Components

Diff Viewer

Preview: Unified

Line diff (jsdiff) with optional word-level highlights, unified or split. Signs and line numbers carry meaning, not color alone.

Import

import { DiffViewer } from '@marbleui/ui'

Props

<DiffViewer>

PropTypeDefaultDescription
newText *requiredstring—
oldText *requiredstring—
classNamestring—
newTitlestring'After'
oldTitlestring'Before'
view'split' | 'unified''unified'unified: one column with -/+ lines. split: old and new side by side.
wordDiffbooleantrueHighlight changed words inside modified lines.

Usage notes

Line-by-line comparison of two versions of a text, with changed words highlighted. To show one version with syntax highlighting use CodeBlock.

<DiffViewer oldTitle="button.tsx" newTitle="button.tsx" oldText={previous} newText={current} />
  • Pass both full texts; the diff is computed in the browser with jsdiff. It doesn’t accept a patch, has no syntax highlighting, and renders every line (unchanged stretches aren’t collapsed).
  • view="unified" (default) is one column with old and new line numbers. view="split" puts them side by side, padding the shorter side of each change so lines stay aligned, and wraps long lines. Unified scrolls sideways instead of wrapping.
  • Each line carries a +/− sign and line numbers, so changes don’t rely on color. The header shows the file name (old → new when the titles differ) and the added/removed line counts.
  • wordDiff={false} turns off the in-line word highlights.
Example source · show
import { DiffViewer } from './diff-viewer'

const before = `export function Button({ variant, ...props }) {
  return (
    <AriaButton
      {...props}
      className={buttonStyles({ variant })}
    />
  )
}`
const after = `export function Button({ variant, size, ...props }) {
  return (
    <AriaButton
      {...props}
      className={composeRenderProps(props.className, (cls, rp) =>
        buttonStyles({ ...rp, variant, size, className: cls }),
      )}
    />
  )
}`

export const styles = {
  Unified: () => <DiffViewer className="w-[40rem]" oldTitle="button.tsx" newTitle="button.tsx" oldText={before} newText={after} />,
  Split: () => <DiffViewer className="w-[46rem]" view="split" oldTitle="button.tsx" newTitle="button.tsx" oldText={before} newText={after} />,
}

Source: packages/ui/src/diff-viewer/diff-viewer.tsx

Catalog

Category
editor
Priority
Pro
Primitive
custom