Skip to content

Repository files navigation

React Diff Viewer


All Contributors

npm versionnpm downloadsGitHub license

A simple and beautiful text diff viewer component made with Diff and React.

example image

Inspired by the Github diff viewer, it includes features like split view, inline view, word diff, line highlight and more. It is highly customizable and it supports almost all languages.

Most credit goes to Pranesh Ravi who created the original diff viewer. I've just made a few modifications and updated the dependencies so they work with modern stacks.

Install

yarn add react-diff-viewer-continued
# or
npm i react-diff-viewer-continued
# or
pnpm add react-diff-viewer-continued

Usage

importReact,{PureComponent}from'react';importReactDiffViewerfrom'react-diff-viewer-continued';constoldCode=`const a = 10const b = 10const c = () => console.log('foo')if(a > 10) { console.log('bar')}console.log('done')`;constnewCode=`const a = 10const boo = 10if(a === 10) { console.log('bar')}`;classDiffextendsPureComponent{render=()=>{return(<ReactDiffVieweroldValue={oldCode}newValue={newCode}splitView={true}/>);};}

Props

PropTypeDefaultDescription
oldValuestring | Object''Old value as string (or Object if using diffJson).
newValuestring | Object''New value as string (or Object if using diffJson).
splitViewbooleantrueSwitch between unified and split view.
disableWordDiffbooleanfalseShow and hide word diff in a diff line.
compareMethodDiffMethod | (string, string) => diff.Change[]DiffMethod.CHARSUses an existing diff method when a DiffMethod enum is passed. If a function is passed, that function is used as the diff method.

JsDiff text diff method used for diffing strings. Check out the guide to use different methods.
renderGutter(diffData) => ReactNodeundefinedFunction that can be used to render an extra gutter with various information next to the line number.
hideLineNumbersbooleanfalseShow and hide line numbers.
alwaysShowLinesstring[][]List of lines to always be shown, regardless of diff status. 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. extraLinesSurroundingDiff applies to these lines as well.
renderContentfunctionundefinedRender Prop API to render code in the diff viewer. Helpful for syntax highlighting
onLineNumberClickfunctionundefinedEvent handler for line number click. (lineId: string) => void
highlightLinesstring[][]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.
showDiffOnlybooleantrueShows only the diffed lines and folds the unchanged lines
extraLinesSurroundingDiffnumber3Number of extra unchanged lines surrounding the diff. Works along with showDiffOnly.
codeFoldMessageRendererfunctionExpand {number} of lines ...Render Prop API to render code fold message.
stylesobject{}To override style variables and styles. Learn more about overriding styles
useDarkThemebooleantrueTo enable/disable dark theme.
leftTitlestringundefinedColumn title for left section of the diff in split view. This will be used as the only title in inline view.
rightTitlestringundefinedColumn title for right section of the diff in split view. This will be ignored in inline view.
linesOffsetnumber0Number to start count code lines from.

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

// Load Prism CSS
<linkhref="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/prism.min.css"
/>
// Load Prism JS
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/prism.min.js"></script>
importReact,{PureComponent}from'react';importReactDiffViewerfrom'react-diff-viewer';constoldCode=`const a = 10const b = 10const c = () => console.log('foo')if(a > 10) { console.log('bar')}console.log('done')`;constnewCode=`const a = 10const boo = 10if(a === 10) { console.log('bar')}`;classDiffextendsPureComponent{highlightSyntax=(str)=>(<prestyle={{display: 'inline'}}dangerouslySetInnerHTML={{__html: Prism.highlight(str,Prism.languages.javascript),}}/>);render=()=>{return(<ReactDiffVieweroldValue={oldCode}newValue={newCode}splitView={true}renderContent={this.highlightSyntax}/>);};}

Text block diff comparison

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.

enumDiffMethod{CHARS='diffChars',WORDS='diffWords',WORDS_WITH_SPACE='diffWordsWithSpace',LINES='diffLines',TRIMMED_LINES='diffTrimmedLines',SENTENCES='diffSentences',CSS='diffCss',}
importReact,{PureComponent}from'react';importReactDiffViewer,{DiffMethod}from'react-diff-viewer';constoldCode=`{ "name": "Original name", "description": null}`;constnewCode=`{ "name": "My updated name", "description": "Brand new description", "status": "running"}`;classDiffextendsPureComponent{render=()=>{return(<ReactDiffVieweroldValue={oldCode}newValue={newCode}compareMethod={DiffMethod.WORDS}splitView={true}/>);};}

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.

// Default variables and style keysconstdefaultStyles={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 objectdiffRemoved?: {},// style objectdiffAdded?: {},// style objectmarker?: {},// style objectemptyGutter?: {},// style objecthighlightedLine?: {},// style objectlineNumber?: {},// style objecthighlightedGutter?: {},// style objectcontentText?: {},// style objectgutter?: {},// style objectline?: {},// style objectwordDiff?: {},// style objectwordAdded?: {},// style objectwordRemoved?: {},// style objectcodeFoldGutter?: {},// style objectcodeFold?: {},// style objectemptyLine?: {},// style objectcontent?: {},// style objecttitleBlock?: {},// style objectsplitView?: {},// 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.

importReact,{PureComponent}from'react';importReactDiffViewerfrom'react-diff-viewer';constoldCode=`const a = 10const b = 10const c = () => console.log('foo')if(a > 10) { console.log('bar')}console.log('done')`;constnewCode=`const a = 10const boo = 10if(a === 10) { console.log('bar')}`;classDiffextendsPureComponent{highlightSyntax=(str)=>(<spanstyle={{display: 'inline'}}dangerouslySetInnerHTML={{__html: Prism.highlight(str,Prism.languages.javascript),}}/>);render=()=>{constnewStyles={variables: {dark: {highlightBackground: '#fefed5',highlightGutterBackground: '#ffcd3c',},},line: {padding: '10px 2px','&:hover': {background: '#a26ea1',},},};return(<ReactDiffViewerstyles={newStyles}oldValue={oldCode}newValue={newCode}splitView={true}renderContent={this.highlightSyntax}/>);};}

Local Development

pnpm install
pnpm build # or use yarn build:watch
pnpm start:examples

Check package.json for more build scripts.

Contributors

Eric M.
Eric M.

💻
Andrei Kovalevsky
Andrei Kovalevsky

💻
Chang Hyun Kim
Chang Hyun Kim

💻

License

MIT

About

A simple and beautiful text diff viewer component made with Diff and React.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages