MrWangJustToDo/git-diff-view

A Diff View component for React / Vue / Solid / Svelte / Ink, same as Github

TypeScript

743

553 commits

updated Oct 17, 2026

See the code

See what people are saying

README

logo

Git Diff View

A high-performance, feature-rich diff view component for React / Vue / Solid / Svelte / Lynx

Deploy NPM Downloads NPM License

✨ Highlights

  • 🎨 Full Syntax Highlighting - HAST AST highlighting via Lowlight / Shiki / Lezer
  • ⚡ High Performance - Web Worker & Node Server support, template mode optimization
  • 🎯 Framework Agnostic - React, Vue, Solid, Svelte, Lynx (ReactLynx), and CLI support
  • 🔧 Highly Customizable - Widgets, extend data, themes, and flexible rendering
  • 📦 Multiple Modes - Git diff or file comparison with Split/Unified views
  • 🌗 SSR/RSC Ready - Full server-side rendering and React Server Components support

🎮 Live Demo

Try it online: Git Playground · File Playground · GitHub Style

git mode

📸 More Screenshots

full feature file mode theme support unified view cli diff view

📦 Installation

# React
pnpm add @git-diff-view/react

# Vue
pnpm add @git-diff-view/vue

# Solid / Svelte
pnpm add @git-diff-view/solid
pnpm add @git-diff-view/svelte

# ReactLynx (Lynx)
pnpm add @git-diff-view/lynx

# CLI (terminal / Ink)
pnpm add @git-diff-view/cli

View Examples for React / Vue / Solid / Svelte / Lynx

🚀 Quick Start

React

import { DiffView, DiffModeEnum } from "@git-diff-view/react";
import "@git-diff-view/react/styles/diff-view.css";

<DiffView
  data={{
    oldFile: { fileName: "old.ts", content: "..." },
    newFile: { fileName: "new.ts", content: "..." },
    hunks: ["..."]
  }}
  diffViewMode={DiffModeEnum.Split}
  diffViewTheme="dark"
  diffViewHighlight
/>

Advanced Usage

import { DiffFile, generateDiffFile } from "@git-diff-view/file";

// File comparison mode
const file = generateDiffFile(
  "old.ts", oldContent,
  "new.ts", newContent,
  "typescript", "typescript"
);
file.initTheme('dark');
file.init();
file.buildSplitDiffLines();

<DiffView diffFile={file} />

More examples: React · Vue · Solid

CLI (Terminal)

Terminal-based diff viewer built with Ink. Supports Split/Unified views, syntax highlighting, and fixed-height viewport scrolling.

pnpm add @git-diff-view/cli
import { DiffView, DiffModeEnum } from "@git-diff-view/cli";

<DiffView
  data={{ oldFile, newFile, hunks }}
  diffViewMode={DiffModeEnum.Split}
  diffViewTheme="dark"
  diffViewHighlight
  width={120}
  height={20}           // viewport height in visual rows (optional)
  onScrollChange={console.log}
/>

CodeView renders a single file; both components expose scroll ref methods (scrollToTop, scrollDown, getScrollState, etc.) when height is set.

Docs: packages/cli/readme.md · Scroll API · Implementation notes

📚 Packages

UI Frameworks

Core Libraries

Syntax Highlighters

PackageEngineBest for
lowlighthighlight.jsDefault, broad language coverage
shikiTextMate / ShikiHighest accuracy & VS Code themes
lezerCodeMirror LezerConstrained runtimes (e.g. Lynx), no WASM
import { DiffFile } from "@git-diff-view/core";
import { getDiffViewHighlighter } from "@git-diff-view/shiki";
// or: import { highlighter } from "@git-diff-view/lezer";

const highlighter = await getDiffViewHighlighter();
diffFile.initSyntax({ registerHighlighter: highlighter });

Try switching engines in the live demo homepage example (lowlight / shiki / lezer menu).

🎯 Key Features

  • ✅ Split & Unified Views - Switch between side-by-side and unified diff modes
  • ✅ Full Syntax Highlighting - Lowlight, Shiki, or Lezer via the same HAST pipeline
  • ✅ Light & Dark Themes - Built-in theme support with customization
  • ✅ Line Wrapping - Toggle line wrapping for long code lines
  • ✅ Widget System - Add custom interactive widgets to diff lines
  • ✅ Extend Data - Attach and render custom data per line
  • ✅ Web Worker Support - Offload processing for better performance
  • ✅ SSR & RSC - Full server-side rendering support for React and Vue
  • ✅ Diff Match Patch - Enhanced line-level diff with FastDiff template
  • ✅ Multiple Platforms - React, Vue, Solid, Svelte, Lynx, and CLI
  • ✅ CLI Scroll Viewport - Fixed-height terminal viewport with programmatic scroll (@git-diff-view/cli)
  • ✅ Lynx DiffView - Wrap-first Split/Unified on ReactLynx (@git-diff-view/lynx)

⚡ Advanced Features

FastDiff Template

Enhanced line-by-line diff visualization for better readability.

import { setEnableFastDiffTemplate } from '@git-diff-view/core';

setEnableFastDiffTemplate(true);

In FastDiff mode, adjacent small changes are merged by a semantic cleanup by default, so text without word boundaries (e.g. CJK) may be highlighted as a single block between the first and the last change. To highlight each change separately, keep FastDiff enabled and disable the semantic cleanup:

import { setEnableFastDiffTemplate, setEnableDiffSemanticCleanup } from '@git-diff-view/core';

setEnableFastDiffTemplate(true);
setEnableDiffSemanticCleanup(false);

Note: setEnableDiffSemanticCleanup only affects FastDiff mode (setEnableFastDiffTemplate(true)). It has no effect in the default (relative) mode, which always renders the whole changed span as one block.

setEnableDiffSemanticCleanup(false) is not a substitute for setEnableFastDiffTemplate(true) — the two must be used together.

DefaultFastDiff
defaultfastdiff

Range Mode

Display only a portion of the diff by specifying a line number range. This is useful when you want to focus on a specific section of a large diff.

import { DiffFile, SplitSide } from "@git-diff-view/core";

// Create the full diff instance
const diffFile = new DiffFile(/* ... */);
diffFile.init();
diffFile.buildSplitDiffLines();

// Generate a new instance containing only lines 10-50 (based on new file line numbers)
const rangeDiffFile = diffFile.generateInstanceFromLineNumberRange(10, 50);

// Or specify which side's line numbers to use
const rangeDiffFileOld = diffFile.generateInstanceFromLineNumberRange(10, 50, SplitSide.old);
const rangeDiffFileNew = diffFile.generateInstanceFromLineNumberRange(10, 50, SplitSide.new);

<DiffView diffFile={rangeDiffFile} />

API: generateInstanceFromLineNumberRange(start, end, side?)

ParameterTypeDefaultDescription
startnumber-Start line number (must be less than end)
endnumber-End line number
sideSplitSideSplitSide.newWhich file's line numbers to use (SplitSide.old or SplitSide.new)

This method creates a new DiffFile instance containing only the diff lines within the specified range, making it ideal for:

  • Displaying relevant portions of large diffs
  • Creating focused code review experiences
  • Building paginated diff views

Template Mode

Optimized rendering mode enabled by default for better performance. Learn more

📖 API Reference

Component Props

PropTypeDescription
dataDiffDataDiff data with oldFile, newFile, and hunks
diffFileDiffFilePre-processed diff file instance
diffViewModeSplit | UnifiedView mode (default: Split)
diffViewThemelight | darkTheme (default: light)
diffViewHighlightbooleanEnable syntax highlighting
diffViewWrapbooleanEnable line wrapping
diffViewFontSizenumberFont size in pixels
diffViewAddWidgetbooleanEnable widget button
renderWidgetLineFunctionCustom widget renderer
renderExtendLineFunctionCustom extend data renderer
extendDataExtendDataAdditional data per line
onAddWidgetClickFunctionWidget button click handler

Styling

// default style (Pure CSS)
import "@git-diff-view/react/styles/diff-view.css";

// same as diff-view.css
import "@git-diff-view/react/styles/diff-view-pure.css";

Two Usage Modes

1. Direct Data Mode - Pass raw diff data

<DiffView data={{ oldFile, newFile, hunks }} />

2. DiffFile Instance Mode - Pre-process for better control

const file = new DiffFile(/* ... */);
file.init();
file.buildSplitDiffLines();
<DiffView diffFile={file} />

🛠️ Development

git clone https://github.com/MrWangJustToDo/git-diff-view.git
cd git-diff-view
pnpm install
pnpm run build:packages
pnpm run dev:react  # or dev:vue, dev:solid, dev:svelte, dev:cli

CLI scroll tests (after build:packages):

pnpm --filter @git-diff-view/cli test:scroll
pnpm --filter @git-diff-view/cli test:scroll:interactive:diffview

📄 License

MIT © MrWangJustToDo

cli-component
diff
diff-component
diff-view
diff-viewer
file-diff
git-diff
github-diff
react-diff-component
solid-diff-component
svelte-diff-component
two-file-diff
vue-diff-component

MrWangJustToDo/git-diff-view

A Diff View component for React / Vue / Solid / Svelte / Ink, same as Github

TypeScript

743

553 commits

updated Oct 17, 2026

See the code

See what people are saying

README

logo

Git Diff View

A high-performance, feature-rich diff view component for React / Vue / Solid / Svelte / Lynx

Deploy NPM Downloads NPM License

✨ Highlights

  • 🎨 Full Syntax Highlighting - HAST AST highlighting via Lowlight / Shiki / Lezer
  • ⚡ High Performance - Web Worker & Node Server support, template mode optimization
  • 🎯 Framework Agnostic - React, Vue, Solid, Svelte, Lynx (ReactLynx), and CLI support
  • 🔧 Highly Customizable - Widgets, extend data, themes, and flexible rendering
  • 📦 Multiple Modes - Git diff or file comparison with Split/Unified views
  • 🌗 SSR/RSC Ready - Full server-side rendering and React Server Components support

🎮 Live Demo

Try it online: Git Playground · File Playground · GitHub Style

git mode

📸 More Screenshots

full feature file mode theme support unified view cli diff view

📦 Installation

# React
pnpm add @git-diff-view/react

# Vue
pnpm add @git-diff-view/vue

# Solid / Svelte
pnpm add @git-diff-view/solid
pnpm add @git-diff-view/svelte

# ReactLynx (Lynx)
pnpm add @git-diff-view/lynx

# CLI (terminal / Ink)
pnpm add @git-diff-view/cli

View Examples for React / Vue / Solid / Svelte / Lynx

🚀 Quick Start

React

import { DiffView, DiffModeEnum } from "@git-diff-view/react";
import "@git-diff-view/react/styles/diff-view.css";

<DiffView
  data={{
    oldFile: { fileName: "old.ts", content: "..." },
    newFile: { fileName: "new.ts", content: "..." },
    hunks: ["..."]
  }}
  diffViewMode={DiffModeEnum.Split}
  diffViewTheme="dark"
  diffViewHighlight
/>

Advanced Usage

import { DiffFile, generateDiffFile } from "@git-diff-view/file";

// File comparison mode
const file = generateDiffFile(
  "old.ts", oldContent,
  "new.ts", newContent,
  "typescript", "typescript"
);
file.initTheme('dark');
file.init();
file.buildSplitDiffLines();

<DiffView diffFile={file} />

More examples: React · Vue · Solid

CLI (Terminal)

Terminal-based diff viewer built with Ink. Supports Split/Unified views, syntax highlighting, and fixed-height viewport scrolling.

pnpm add @git-diff-view/cli
import { DiffView, DiffModeEnum } from "@git-diff-view/cli";

<DiffView
  data={{ oldFile, newFile, hunks }}
  diffViewMode={DiffModeEnum.Split}
  diffViewTheme="dark"
  diffViewHighlight
  width={120}
  height={20}           // viewport height in visual rows (optional)
  onScrollChange={console.log}
/>

CodeView renders a single file; both components expose scroll ref methods (scrollToTop, scrollDown, getScrollState, etc.) when height is set.

Docs: packages/cli/readme.md · Scroll API · Implementation notes

📚 Packages

UI Frameworks

Core Libraries

Syntax Highlighters

PackageEngineBest for
lowlighthighlight.jsDefault, broad language coverage
shikiTextMate / ShikiHighest accuracy & VS Code themes
lezerCodeMirror LezerConstrained runtimes (e.g. Lynx), no WASM
import { DiffFile } from "@git-diff-view/core";
import { getDiffViewHighlighter } from "@git-diff-view/shiki";
// or: import { highlighter } from "@git-diff-view/lezer";

const highlighter = await getDiffViewHighlighter();
diffFile.initSyntax({ registerHighlighter: highlighter });

Try switching engines in the live demo homepage example (lowlight / shiki / lezer menu).

🎯 Key Features

  • ✅ Split & Unified Views - Switch between side-by-side and unified diff modes
  • ✅ Full Syntax Highlighting - Lowlight, Shiki, or Lezer via the same HAST pipeline
  • ✅ Light & Dark Themes - Built-in theme support with customization
  • ✅ Line Wrapping - Toggle line wrapping for long code lines
  • ✅ Widget System - Add custom interactive widgets to diff lines
  • ✅ Extend Data - Attach and render custom data per line
  • ✅ Web Worker Support - Offload processing for better performance
  • ✅ SSR & RSC - Full server-side rendering support for React and Vue
  • ✅ Diff Match Patch - Enhanced line-level diff with FastDiff template
  • ✅ Multiple Platforms - React, Vue, Solid, Svelte, Lynx, and CLI
  • ✅ CLI Scroll Viewport - Fixed-height terminal viewport with programmatic scroll (@git-diff-view/cli)
  • ✅ Lynx DiffView - Wrap-first Split/Unified on ReactLynx (@git-diff-view/lynx)

⚡ Advanced Features

FastDiff Template

Enhanced line-by-line diff visualization for better readability.

import { setEnableFastDiffTemplate } from '@git-diff-view/core';

setEnableFastDiffTemplate(true);

In FastDiff mode, adjacent small changes are merged by a semantic cleanup by default, so text without word boundaries (e.g. CJK) may be highlighted as a single block between the first and the last change. To highlight each change separately, keep FastDiff enabled and disable the semantic cleanup:

import { setEnableFastDiffTemplate, setEnableDiffSemanticCleanup } from '@git-diff-view/core';

setEnableFastDiffTemplate(true);
setEnableDiffSemanticCleanup(false);

Note: setEnableDiffSemanticCleanup only affects FastDiff mode (setEnableFastDiffTemplate(true)). It has no effect in the default (relative) mode, which always renders the whole changed span as one block.

setEnableDiffSemanticCleanup(false) is not a substitute for setEnableFastDiffTemplate(true) — the two must be used together.

DefaultFastDiff
defaultfastdiff

Range Mode

Display only a portion of the diff by specifying a line number range. This is useful when you want to focus on a specific section of a large diff.

import { DiffFile, SplitSide } from "@git-diff-view/core";

// Create the full diff instance
const diffFile = new DiffFile(/* ... */);
diffFile.init();
diffFile.buildSplitDiffLines();

// Generate a new instance containing only lines 10-50 (based on new file line numbers)
const rangeDiffFile = diffFile.generateInstanceFromLineNumberRange(10, 50);

// Or specify which side's line numbers to use
const rangeDiffFileOld = diffFile.generateInstanceFromLineNumberRange(10, 50, SplitSide.old);
const rangeDiffFileNew = diffFile.generateInstanceFromLineNumberRange(10, 50, SplitSide.new);

<DiffView diffFile={rangeDiffFile} />

API: generateInstanceFromLineNumberRange(start, end, side?)

ParameterTypeDefaultDescription
startnumber-Start line number (must be less than end)
endnumber-End line number
sideSplitSideSplitSide.newWhich file's line numbers to use (SplitSide.old or SplitSide.new)

This method creates a new DiffFile instance containing only the diff lines within the specified range, making it ideal for:

  • Displaying relevant portions of large diffs
  • Creating focused code review experiences
  • Building paginated diff views

Template Mode

Optimized rendering mode enabled by default for better performance. Learn more

📖 API Reference

Component Props

PropTypeDescription
dataDiffDataDiff data with oldFile, newFile, and hunks
diffFileDiffFilePre-processed diff file instance
diffViewModeSplit | UnifiedView mode (default: Split)
diffViewThemelight | darkTheme (default: light)
diffViewHighlightbooleanEnable syntax highlighting
diffViewWrapbooleanEnable line wrapping
diffViewFontSizenumberFont size in pixels
diffViewAddWidgetbooleanEnable widget button
renderWidgetLineFunctionCustom widget renderer
renderExtendLineFunctionCustom extend data renderer
extendDataExtendDataAdditional data per line
onAddWidgetClickFunctionWidget button click handler

Styling

// default style (Pure CSS)
import "@git-diff-view/react/styles/diff-view.css";

// same as diff-view.css
import "@git-diff-view/react/styles/diff-view-pure.css";

Two Usage Modes

1. Direct Data Mode - Pass raw diff data

<DiffView data={{ oldFile, newFile, hunks }} />

2. DiffFile Instance Mode - Pre-process for better control

const file = new DiffFile(/* ... */);
file.init();
file.buildSplitDiffLines();
<DiffView diffFile={file} />

🛠️ Development

git clone https://github.com/MrWangJustToDo/git-diff-view.git
cd git-diff-view
pnpm install
pnpm run build:packages
pnpm run dev:react  # or dev:vue, dev:solid, dev:svelte, dev:cli

CLI scroll tests (after build:packages):

pnpm --filter @git-diff-view/cli test:scroll
pnpm --filter @git-diff-view/cli test:scroll:interactive:diffview

📄 License

MIT © MrWangJustToDo

cli-component
diff
diff-component
diff-view
diff-viewer
file-diff
git-diff
github-diff
react-diff-component
solid-diff-component
svelte-diff-component
two-file-diff
vue-diff-component

Significant stargazers

Christian Bromann

1,483 followers · starred Mar 2026

Vladimir Krivosheev

409 followers · starred Jul 2025

yetone

9,513 followers · starred Jul 2025

LgCuwukii☆

230 followers · starred Feb 2024