React Diff Viewer
May 22, 2020
Kyle Matthews, author of the Gatsbyjs project, tweeted asking whether anyone had made a React component making use of the
Example provided int the VSCode docs
My use case never didn't require the "line-by-line" style comparison for git, but was more focused on an expectation of finding small differences between different people's inputs. I went with an approach that could be customized to either show a diff by letters or by words.
Here's the example I built!
Use with Prism JS
It's also possible to use this for an inline text diff for code samples using Prism js!
var str = "text before diff";
const fooprofessionalVariable = "bar";let textAfterDiff;
This gets a bit tricky, because Prism JS isn't aware of the React lifecycle, and replaces every element inside the target
Also, you will need to modify the React Diff component to run on any text that is included in the string that you want highlighting on. That will end up looking like this:
// PrismDiff.js
import React from "react";
import * as diff from "diff";
import PropTypes from "prop-types";
import Prism from "prismjs";
const styles = {
added: {
color: "green",
backgroundColor: "#b5efdb",
textShadow: "none",
},
removed: {
color: "red",
backgroundColor: "#fec4c0",
textShadow: "none",
},
};
const PrismDiff = ({ string1 = "", string2 = "", mode = "characters" }) => {
let groups = [];
if (mode === "characters") groups = diff.diffChars(string1, string2);
if (mode === "words") groups = diff.diffWords(string1, string2);
const mappedNodes = groups.map(group => {
const { value, added, removed } = group;
let nodeStyles;
if (added) nodeStyles = styles.added;
if (removed) nodeStyles = styles.removed;
// Using dangerouslySetInnerHTML with the Node rendering API
// Note: is dangerous
return (
<span
style={nodeStyles}
dangerouslySetInnerHTML={{
__html: Prism.highlight(
value,
Prism.languages.javascript,
"javascript"
),
}}
/>
);
});
return <span>{mappedNodes}</span>;
};
PrismDiff.propTypes = {
string1: PropTypes.string,
string2: PropTypes.string,
mode: PropTypes.oneOf(["characters", "words"]),
};
export default PrismDiff;
// PrismExample.js
import React, { useLayoutEffect } from "react";
import Prism from "prismjs";
import PrismDiff from "./PrismDiff";
const PrismExample = () => {
useLayoutEffect(() => {
Prism.highlightAll();
}, []);
return (
<pre>
<code className="language-javascript">var str = "text before diff";</code>
{`
`}
<PrismDiff
string1={'const foo = "bar"'}
string2={'const professionalVariable = "bar";'}
mode="words"
/>
{`
`}
<code className="language-javascript">let textAfterDiff;</code>
</pre>
);
};
export default PrismExample;
Hope this helps as you make your own content!
There is also an official Prism js plugin that supports highlighting for line diffs, but I don't think it handles the string comparison for you.