Skip to content

Latest commit

 

History

History
324 lines (233 loc) · 9.7 KB

File metadata and controls

324 lines (233 loc) · 9.7 KB

Vue Diff Text

I needed a way to show text differences in my Vue 3 apps, so I built this wrapper around the fantastic jsdiff library by @kpdecker. It gives you five different ways to highlight changes between text blocks, from character-level precision to sentence-level overview.

Looking for PHP? Check out the sister package php-diff-text — a 1:1 PHP port with the same diffing strategies.

⚠️ Important: This library is designed for text and paragraph comparisons, not code diffing. If you need to compare code with syntax highlighting, use v-code-diff instead.

What you get

  • Works with Vue 3 Composition API
  • Six different diff strategies: characters, words, words with spaces, lines, sentences, and HTML
  • Perfect for text, documents, and prose comparisons
  • Easy to customize with CSS variables
  • Full TypeScript support
  • Lightweight (just a thin wrapper around jsdiff)
  • Pass any options that jsdiff supports

Installation

npm install vue-diff-text

Demo

Vue Diff Text Demo

To run this demo locally: git clone this repo, cd demo, npm install, then npm run dev

The six components

Each component uses a different diffing strategy depending on what level of detail you need:

DiffChars - Shows every single character change. Great for catching typos or small edits.

DiffWords - Highlights word-level changes but ignores whitespace. Perfect for most text editing scenarios.

DiffWordsWithSpace - Like DiffWords but also shows whitespace changes. Useful when formatting matters.

DiffLines - Shows entire line changes. Good for comparing plain text files or when you want a high-level overview.

DiffSentences - Highlights sentence-level changes. Nice for prose and document editing.

DiffHtml - Compares HTML content and highlights markup differences. Perfect for rich text editing and HTML content changes. Supports a similarity-threshold prop to gracefully handle complete content replacements by showing old text as fully deleted and new text as fully added when texts are too dissimilar.

How to use it

⚠️ Important: You should import the CSS file for styling to work. It's not mandatory, you CAN implement the classes yourself.

import 'vue-diff-text/dist/style.css'

Basic example

<template>
  <div>
    <!-- Pick whichever diff type makes sense for your use case -->
    <DiffChars :old-text="oldText" :new-text="newText" />
    <DiffWords :old-text="oldText" :new-text="newText" />
    <DiffWordsWithSpace :old-text="oldText" :new-text="newText" />
    <DiffLines :old-text="oldText" :new-text="newText" />
    <DiffSentences :old-text="oldText" :new-text="newText" />
    <DiffHtml :old-text="oldHtml" :new-text="newHtml" />
  </div>
</template>

<script setup>
import { DiffChars, DiffWords, DiffWordsWithSpace, DiffLines, DiffSentences, DiffHtml } from 'vue-diff-text'
import 'vue-diff-text/dist/style.css'

const oldText = "Hello world"
const newText = "Hello Vue world"
const oldHtml = '<p>Welcome to our <strong>website</strong>!</p>'
const newHtml = '<p>Welcome to our <strong>amazing website</strong>!</p>'
</script>

Passing options

Since this is just a wrapper around jsdiff, you can pass any options that jsdiff supports:

<template>
  <div>
    <!-- Ignore case differences -->
    <DiffWords 
      :old-text="oldText" 
      :new-text="newText" 
      :options="{ ignoreCase: true }"
    />
    
    <!-- Ignore whitespace when comparing lines -->
    <DiffLines 
      :old-text="oldText" 
      :new-text="newText" 
      :options="{ ignoreWhitespace: true }"
    />
  </div>
</template>

<script setup>
import { DiffWords, DiffLines } from 'vue-diff-text'
import 'vue-diff-text/dist/style.css'

const oldText = "Hello WORLD"
const newText = "hello world"
</script>

Props

All components take the same props:

  • old-text (required) - The original text
  • new-text (required) - The new text to compare
  • options (optional) - Any options to pass to jsdiff
  • similarity-threshold (optional, DiffHtml only) - Number between 0 and 1. When set, if the text similarity falls below this threshold, the diff renders as a full replacement (all old text deleted, all new text added) instead of word-level diffing. Recommended value: 0.3. Default: null (disabled).

Options

The options you can pass depend on which diff type you're using. Here are the most common ones:

For most components:

  • ignoreCase: true - Ignore case differences
  • ignoreWhitespace: true - Ignore whitespace differences

For DiffLines:

  • newlineIsToken: true - Treat newlines as separate tokens

Check the jsdiff docs for the complete list of what each diff type supports.

Handling large replacements (DiffHtml)

When text is completely rewritten, word-level diffs can produce unreadable results by finding incidental word matches. The similarity-threshold prop fixes this:

<DiffHtml
  :old-text="oldHtml"
  :new-text="newHtml"
  :similarity-threshold="0.3"
/>

When set, DiffHtml computes text similarity. If below the threshold, it shows the old text as fully deleted and the new text as fully added — just like Google Docs or GitHub handles complete rewrites. The threshold is a number between 0-1 (0.3 = 30% similarity).

Styling

You must import the CSS file for styling to work. Add this import to your component or main.js:

import 'vue-diff-text/dist/style.css'

You can then customize the look in two ways:

CSS variables (easiest)

Just override the CSS variables to change colors:

:root {
  --text-diff-added-bg: #e6ffed;
  --text-diff-added-color: #1b7332;
  --text-diff-removed-bg: #ffe6e6;
  --text-diff-removed-color: #d73a49;
  --text-diff-removed-decoration: line-through;
}

Direct CSS classes

If you need more control, target these classes. Note that all styles are scoped under .text-diff:

.text-diff {
  white-space: pre-wrap;
  word-wrap: break-word;
  /* Add your custom container styles here */
}

.text-diff .diff-added {
  background-color: #e6ffed;
  color: #1b7332;
  font-weight: bold;
  border-radius: 3px;
  padding: 2px 4px;
}

.text-diff .diff-removed {
  background-color: #ffe6e6;
  color: #d73a49;
  text-decoration: line-through;
  border-radius: 3px;
  padding: 2px 4px;
}

The available classes are:

  • .text-diff - Main container (each component has this)
  • .text-diff .diff-added - Added text spans
  • .text-diff .diff-removed - Removed text spans

Note: The DiffHtml component uses the same CSS classes (.diff-added and .diff-removed) as the other components for consistent styling.

Development

Want to contribute or just mess around with the code? Here's how to get started.

Setup

You'll need Node.js 18+ and npm (or yarn, whatever you prefer).

git clone https://github.com/sitefinitysteve/vue-diff-text.git
cd vue-diff-text
npm install

Working on it

The easiest way to develop is to use the demo app with hot reload:

cd demo
npm run dev

This spins up a dev server (usually at http://localhost:5173) where you can see all the components in action. The demo is set up with Vite aliases so it points directly to the source files - no build step needed.

Just edit the files in src/components/ and your changes will show up instantly.

If you want to test the built version instead:

npm run build
cd demo
npm run dev

Building

When you're ready to build:

npm run build

This creates the dist files (ES module, UMD bundle, TypeScript declarations, and CSS).

Testing

The demo folder has a complete Vue 3 app for testing. It lets you:

  • Edit text in real-time and see the diffs
  • Compare all five diff types side by side
  • Test different options
  • Try it with longer text blocks
cd demo
npm install  # First time only
npm run dev

Project layout

vue-diff-text/
├── src/
│   ├── components/          # The five diff components
│   └── index.ts            # Main entry point
├── demo/                   # Test app
├── dist/                   # Built files
└── package.json

Available scripts:

  • npm run dev - Start dev server
  • npm run build - Build for production
  • npm run preview - Preview built version

For the demo (run from demo/):

  • npm run dev - Start demo server
  • npm run build - Build demo
  • npm run preview - Preview built demo

Dependencies

  • vue ^3.4.21 - Vue 3 framework
  • diff ^5.2.0 - The core diffing library by @kpdecker that does all the heavy lifting
  • diffblazer ^1.0.0 - Fast HTML diffing library used by the DiffHtml component

Contributing

Found a bug or want to add a feature? Pull requests are welcome!

  1. Fork it
  2. Create your feature branch
  3. Make your changes
  4. Test it in the demo app
  5. Commit and push
  6. Open a pull request

License

MIT © Steve McNiven-Scott

Thanks

Huge thanks to @kpdecker for creating and maintaining jsdiff. This library wouldn't exist without his excellent work on the underlying diffing algorithms.

Links