Much thanks to the people who replied. I amusingly came to a solution. Hopefully this helps other people with this problem.
The concept is that I have two editable textboxes with content, and I highlight the differences between the two. Firstly, let's address the highlighting. This is straightforward. I used Squiggs's method of comparing two strings by using the following package:
https://github.com/kpdecker/jsdiff
Utilizing the Diff
package, I created a function that compares the two strings and returns a result:
function compareStrings(string1, string2) {
let results = Diff.diffChars(string1, string2);
let output = "";
results.forEach((item) => {
if (item.removed) {
output += `<span style="background-color:yellow">${item.value}</span>`;
} else if (!item.added) {
output += `${item.value}`;
}
});
return output;
}
When using the Diff
package, it separates the identified differences and similarities into different items. It makes working with the findings relatively easy. In the code above, the results in results
are iterated over. If an item has removed
set to true, it's an item in string1
that's not in string2
. If added
is set to true, its an item in string2
that's not in string1
. If neither are set to true, it's an item in both strings. The output of my function will contain all the characters of string1
. If a item has added
set to true, the item is ignored. For example, if string1
is cat
and string2
is bat
, output
will be cat
but with c
highlighted in yellow.
So how do I insert this highlighted text into a Material-Ui textbox? Well, I chose to go down the route of utilizing a contentEditable control. You can transform a p
tag (and other tags) to an editable textbox that renders HTML. This isn't a solution that I love since it opens up the hassle of dealing with XSS, but it seems unavoidable. If anyone follows this solution, I implore you to implement client-side and server-side input sanitation to prevent XSS. The latter is especially important because client-side validation can be bypassed rather easily through various methods, such as modifying the page with inspect element or by utilizing packet crafting tools.
Here's how a contentEditable textbox looks like in HTML:
<p
id="textbox1"
className="textbox"
variant="outlined"
contentEditable={true}
/>
From here, I can assign the results of compareStrings
to it:
document.getElementById("textbox1").innerHTML = htmlData
So the end result would have two contentEditable textboxes. I would have to invoke compareStrings twice and apply the results to both.
Of course, I've only detailed just the essentials to solve this problem. There's other quality of life features such as copy and paste as detailed below:
Highlight value of @material-ui/core TextField in React at specific indices