A simple and beautiful text diff viewer component with comment box support made with diff and React
npm install react-diff-comment-viewer




A simple and beautiful text diff viewer component made with Diff and React.
Inspired from Github diff viewer, it includes features like split view, inline view, word diff, line highlight, comment box and more. It is highly customizable and it supports almost all languages.
Check here for v2.0
``bash
yarn add react-diff-comment-viewer
npm i react-diff-comment-viewer
`
`javascript
import React, { PureComponent } from 'react';
import ReactDiffViewer from 'react-diff-comment-viewer';
const oldCode =
const a = 10
const b = 10
const c = () => console.log('foo')
if(a > 10) {
console.log('bar')
}
console.log('done');
const newCode =
const a = 10
const boo = 10
if(a === 10) {
console.log('bar')
};
class Diff extends PureComponent {
render = () => {
return (
);
};
}
`
`javascript
import React, { PureComponent } from 'react';
import ReactDiffViewer from 'react-diff-comment-viewer';
import CommentBox from 'react-diff-comment-viewer/CommentBox';
const oldCode = const a = 10;;const a = 20;
const newCode = ;
const comments = [
{
id: '1',
author: 'John Doe',
handle: 'johndoe',
role: 'Reviewer',
content: 'This change looks good!',
timestamp: new Date(),
replies: []
}
];
class Diff extends PureComponent {
render = () => {
return (
newValue={newCode}
splitView={true}
useDarkTheme={false}
showDiffOnly={false}
leftTitle="Old File"
rightTitle="New File"
commentRow={
Props
| Prop | Type | Default | Description |
| ------------------------- | --------------- | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| oldValue |
string | '' | Old value as string. |
| newValue | string | '' | New value as string. |
| splitView | boolean | true | Switch between unified and split view. |
| disableWordDiff | boolean | false | Show and hide word diff in a diff line. |
| compareMethod | DiffMethod | DiffMethod.CHARS | JsDiff text diff method used for diffing strings. Check out the guide to use different methods. |
| hideLineNumbers | boolean | false | Show and hide line numbers. |
| renderContent | function | undefined | Render Prop API to render code in the diff viewer. Helpful for syntax highlighting |
| onLineNumberClick | function | undefined | Event handler for line number click. (lineId: string) => void |
| highlightLines | array[string] | [] | List of lines to be highlighted. Works together with onLineNumberClick. Line number are prefixed with L and R for the left and right section of the diff viewer, respectively. For example, L-20 means 20th line in the left pane. To highlight a range of line numbers, pass the prefixed line number as an array. For example, [L-2, L-3, L-4, L-5] will highlight the lines 2-5 in the left pane. |
| showDiffOnly | boolean | true | Shows only the diffed lines and folds the unchanged lines |
| extraLinesSurroundingDiff | number | 3 | Number of extra unchanged lines surrounding the diff. Works along with showDiffOnly. |
| codeFoldMessageRenderer | function | Expand {number} of lines ... | Render Prop API to render code fold message. |
| styles | object | {} | To override style variables and styles. Learn more about overriding styles |
| useDarkTheme | boolean | true | To enable/disable dark theme. |
| fontSize | string\|number | '14px' | Font size for code lines. Can be a string (e.g., '16px') or a number (e.g., 16 which will be converted to '16px'). The "Expand * lines ..." text will automatically be 2px smaller than the code font size. |
| leftTitle | string | undefined | Column title for left section of the diff in split view. This will be used as the only title in inline view. |
| rightTitle | string | undefined | Column title for right section of the diff in split view. This will be ignored in inline view. |
| linesOffset | number | 0 | Number to start count code lines from. |
| commentRow | JSX.Element | undefined | Comment box content to display alongside the diff. This will be shown in a separate column in split view mode. The comment box will span from commentRowLineNumber to commentRowEndLineNumber. |
| commentRowLineNumber | number | undefined | Starting line number (0-based index) where the comment box should be displayed. The comment box will start from this line. |
| commentRowEndLineNumber | number | undefined | Ending line number (0-based index) where the comment box should end. The comment box will span from commentRowLineNumber to this line. If not provided, the comment box will span from the start line to the end of the diff. |Instance Methods
resetCodeBlocks() - Resets the expanded code blocks to it's initial state. Return true on successful reset and false during unsuccessful reset.Syntax Highlighting
Syntax highlighting is a bit tricky when combined with diff. Here, React Diff Viewer provides a simple render prop API to handle syntax highlighting. Use
renderContent(content: string) => JSX.Element and your favorite syntax highlighting library to achieve this.An example using Prism JS
`html
// Load Prism CSS
href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/prism.min.css"
/>// Load Prism JS
``javascript
import React, { PureComponent } from 'react';
import ReactDiffViewer from 'react-diff-comment-viewer';const oldCode =
if(a > 10) {
console.log('bar')
}
console.log('done');
const newCode =
const a = 10
const boo = 10
if(a === 10) {
console.log('bar')
};
class Diff extends PureComponent {
highlightSyntax = str => (
render = () => {
return (
newValue={newCode}
splitView={true}
renderContent={this.highlightSyntax}
/>
);
};
}
`
Different styles of text block diffing are possible by using the enums corresponding to variou JsDiff methods (learn more). The supported methods are as follows.
`javascript`
enum DiffMethod {
CHARS = 'diffChars',
WORDS = 'diffWords',
WORDS_WITH_SPACE = 'diffWordsWithSpace',
LINES = 'diffLines',
TRIMMED_LINES = 'diffTrimmedLines',
SENTENCES = 'diffSentences',
CSS = 'diffCss',
}
`javascript
import React, { PureComponent } from 'react';
import ReactDiffViewer, { DiffMethod } from 'react-diff-comment-viewer';
const oldCode =
{
"name": "Original name",
"description": null
};
const newCode =
{
"name": "My updated name",
"description": "Brand new description",
"status": "running"
};
class Diff extends PureComponent {
render = () => {
return (
newValue={newCode}
compareMethod={DiffMethod.WORDS}
splitView={true}
/>
);
};
}
`
React Diff Viewer supports displaying comment boxes alongside the diff view. This is useful for code review scenarios where you want to add comments to specific lines of code.
The CommentBox component is a built-in component for displaying comments. You can import it separately:
`javascript`
import CommentBox from 'react-diff-comment-viewer/CommentBox';
| Prop | Type | Default | Description |
| ------------- | ------------------------- | ----------- | ---------------------------------------------- |
| comments | Comment[] | [] | Array of comment objects to display |boolean
| showAvatar | | true | Whether to show user avatars |boolean
| useDarkTheme | | false | Whether to use dark theme |CommentBoxStylesOverride
| styles | | {} | Style overrides for the comment box |
`typescript`
interface Comment {
id: string; // Unique identifier for the comment
author: string; // Author name
handle?: string; // Author handle/username
role?: string; // Author role (e.g., "Reviewer", "Maintainer")
content: string; // Comment content/text
timestamp: Date; // Comment timestamp
avatar?: string; // Avatar image URL
replies?: Comment[]; // Nested replies to this comment
}
`javascript
import React, { PureComponent } from 'react';
import ReactDiffViewer from 'react-diff-comment-viewer';
import CommentBox from 'react-diff-comment-viewer/CommentBox';
const oldCode =
function calculate(a, b) {
return a + b;
};
const newCode =
function calculate(a, b) {
return a * b;
};
const comments = [
{
id: '1',
author: 'Alice',
handle: 'alice',
role: 'Reviewer',
content: 'Please consider using multiplication instead of addition.',
timestamp: new Date(Date.now() - 3 60 60 * 1000), // 3 hours ago
replies: [
{
id: '2',
author: 'Bob',
handle: 'bob',
role: 'Author',
content: 'Good catch! Updated.',
timestamp: new Date(Date.now() - 2 60 60 * 1000), // 2 hours ago
replies: []
}
]
}
];
class DiffWithComments extends PureComponent {
render = () => {
return (
newValue={newCode}
splitView={true}
useDarkTheme={false}
showDiffOnly={false}
leftTitle="Old Code"
rightTitle="New Code"
commentRow={
$3
- Line Range Support: Comments can be displayed for a specific range of lines using
commentRowLineNumber and commentRowEndLineNumber. Note that line numbers are 0-based (start from 0).
- Nested Replies: Comments support nested replies for threaded discussions
- Avatar Support: Display user avatars with comments
- Dark Theme: Support for both light and dark themes
- Customizable Styles: Override styles using the styles prop
- Split View Only: Comment boxes are currently only supported in split view mode
- Visual Highlighting: Lines within the comment range are highlighted with a light blue background in split view mode$3
The comment box uses a blue left border (
#0066cc) and gray borders for the other sides. You can customize the styling by passing a styles prop to the CommentBox component.Overriding Styles
React Diff Viewer uses emotion for styling. It also offers a simple way to override styles and style variables. You can supply different variables for both light and dark themes. Styles will be common for both themes.
Below are the default style variables and style object keys.
`javascript// Default variables and style keys
const defaultStyles = {
variables: {
light: {
diffViewerBackground: '#fff',
diffViewerColor: '#212529',
addedBackground: '#e6ffed',
addedColor: '#24292e',
removedBackground: '#ffeef0',
removedColor: '#24292e',
wordAddedBackground: '#acf2bd',
wordRemovedBackground: '#fdb8c0',
addedGutterBackground: '#cdffd8',
removedGutterBackground: '#ffdce0',
gutterBackground: '#f7f7f7',
gutterBackgroundDark: '#f3f1f1',
highlightBackground: '#fffbdd',
highlightGutterBackground: '#fff5b1',
codeFoldGutterBackground: '#dbedff',
codeFoldBackground: '#f1f8ff',
emptyLineBackground: '#fafbfc',
gutterColor: '#212529',
addedGutterColor: '#212529',
removedGutterColor: '#212529',
codeFoldContentColor: '#212529',
diffViewerTitleBackground: '#fafbfc',
diffViewerTitleColor: '#212529',
diffViewerTitleBorderColor: '#eee',
},
dark: {
diffViewerBackground: '#2e303c',
diffViewerColor: '#FFF',
addedBackground: '#044B53',
addedColor: 'white',
removedBackground: '#632F34',
removedColor: 'white',
wordAddedBackground: '#055d67',
wordRemovedBackground: '#7d383f',
addedGutterBackground: '#034148',
removedGutterBackground: '#632b30',
gutterBackground: '#2c2f3a',
gutterBackgroundDark: '#262933',
highlightBackground: '#2a3967',
highlightGutterBackground: '#2d4077',
codeFoldGutterBackground: '#21232b',
codeFoldBackground: '#262831',
emptyLineBackground: '#363946',
gutterColor: '#464c67',
addedGutterColor: '#8c8c8c',
removedGutterColor: '#8c8c8c',
codeFoldContentColor: '#555a7b',
diffViewerTitleBackground: '#2f323e',
diffViewerTitleColor: '#555a7b',
diffViewerTitleBorderColor: '#353846',
}
},
diffContainer?: {}, // style object
diffRemoved?: {}, // style object
diffAdded?: {}, // style object
marker?: {}, // style object
emptyGutter?: {}, // style object
highlightedLine?: {}, // style object
lineNumber?: {}, // style object
highlightedGutter?: {}, // style object
contentText?: {}, // style object
gutter?: {}, // style object
line?: {}, // style object
wordDiff?: {}, // style object
wordAdded?: {}, // style object
wordRemoved?: {}, // style object
codeFoldGutter?: {}, // style object
codeFold?: {}, // style object
emptyLine?: {}, // style object
content?: {}, // style object
titleBlock?: {}, // style object
splitView?: {}, // style object
}
`To override any style, just pass the new style object to the
styles prop. New style will be computed using Object.assign(default, override).For keys other than
variables, the value can either be an object or string interpolation.`javascript
import React, { PureComponent } from 'react';
import ReactDiffViewer from 'react-diff-comment-viewer';const oldCode =
if(a > 10) {
console.log('bar')
}
console.log('done');
const newCode =
const a = 10
const boo = 10
if(a === 10) {
console.log('bar')
};
class Diff extends PureComponent {
highlightSyntax = str => (
style={{ display: 'inline' }}
dangerouslySetInnerHTML={{
__html: Prism.highlight(str, Prism.languages.javascript),
}}
/>
);
render = () => {
const newStyles = {
variables: {
dark: {
highlightBackground: '#fefed5',
highlightGutterBackground: '#ffcd3c',
},
},
line: {
padding: '10px 2px',
'&:hover': {
background: '#a26ea1',
},
},
};
return (
oldValue={oldCode}
newValue={newCode}
splitView={true}
renderContent={this.highlightSyntax}
/>
);
};
}
`
`bash``
yarn install
yarn build # or use yarn build:watch
yarn start:examples
Check package.json for more build scripts.
MIT