npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@akhildesai20/sentencehighlighter

v2.0.1

Published

A lightweight, zero-dependency JavaScript library for sentence-by-sentence highlighting in contenteditable elements

Readme

Sentence Highlighter

Version License Size Zero Dependencies npm npm downloads

A lightweight, zero-dependency JavaScript library for highlighting sentences one at a time as you type. Perfect for distraction-free writing tools, focus apps, and typewriter-style editors.

Created by: AKHIL DESAI
Email: [email protected]
LinkedIn: @akhildesai20

Features

  • 🎯 Sentence-by-sentence highlighting - Automatically highlights the sentence containing your cursor
  • 🎨 Focus mode - Dims non-active sentences for better focus
  • 📝 Heading support - Recognizes headings (H1-H3) as complete sentences
  • Lightweight - No dependencies, ~8KB minified
  • 🔧 Highly configurable - Customizable classes, behavior, and callbacks
  • 📱 Works everywhere - Works with any contenteditable element
  • 🚀 Performance optimized - Uses virtual sentence model, CSS-based highlighting, and incremental updates

🚀 Quick Start

Try it live: View Demo

Installation

Option 1: Download and Include

Download sentence-highlighter.js and include it in your HTML:

<script src="sentence-highlighter.js"></script>

Option 2: CDN (via npm/unpkg)

<script src="https://unpkg.com/@akhildesai20/sentencehighlighter@latest/sentence-highlighter.min.js"></script>

Or via jsDelivr:

<script src="https://cdn.jsdelivr.net/npm/@akhildesai20/sentencehighlighter@latest/sentence-highlighter.min.js"></script>

Or via GitHub:

<script src="https://cdn.jsdelivr.net/gh/akhildesai20/sentence-highlighter@main/sentence-highlighter.min.js"></script>

Option 3: npm

npm install @akhildesai20/sentencehighlighter
// ES6 modules
import SentenceHighlighter from '@akhildesai20/sentencehighlighter';

// CommonJS
const SentenceHighlighter = require('@akhildesai20/sentencehighlighter');

TypeScript support included! The package includes TypeScript definitions.

Quick Start

Basic Usage

<!DOCTYPE html>
<html>
<head>
  <style>
    #editor {
      width: 100%;
      min-height: 300px;
      padding: 20px;
      border: 1px solid #ddd;
      font-size: 18px;
      line-height: 1.7;
    }
  </style>
</head>
<body>
  <div id="editor" contenteditable="true">
    Start typing here. Each sentence will be highlighted as you write.
  </div>

  <script src="sentence-highlighter.js"></script>
  <script>
    const editor = document.getElementById('editor');
    const highlighter = new SentenceHighlighter(editor);
  </script>
</body>
</html>

That's it! The library will automatically:

  • Detect sentences as you type
  • Highlight the sentence containing your cursor
  • Dim other sentences (focus mode)

API Reference

Constructor

const highlighter = new SentenceHighlighter(editorElement, options);

Parameters:

  • editorElement (HTMLElement, required) - The contenteditable element to attach to
  • options (Object, optional) - Configuration options

Options

{
  // CSS Classes
  sentenceClass: 'sentence',                    // Class for all sentences
  activeSentenceClass: 'sentence--active',      // Class for active sentence
  containerClass: 'paragraph',                  // Class for container div
  
  // Data Attributes (for CSS targeting)
  sentenceDataAttribute: 'data-sentence-id',    // Data attribute on sentence spans
  activeSentenceDataAttribute: 'data-sentence-active', // Data attribute on active sentence

  // Behavior
  enableFocusMode: true,                        // Enable focus mode (dim non-active)
  focusModeDimOpacity: 0.18,                   // Opacity for dimmed sentences
  autoScroll: true,                             // Auto-scroll to keep caret centered
  scrollBehavior: 'smooth',                     // 'smooth' or 'auto'

  // Sentence Detection
  headingTags: ['h1', 'h2', 'h3'],             // Tags treated as complete sentences (currently not used)
  sentenceEndings: ['.', '!', '?'],            // Characters that end sentences

  // Performance
  updateDebounce: 100,                          // Debounce time in ms for input events
  updateThrottle: 50,                           // Throttle time in ms for navigation events

  // Callbacks
  onSentenceChange: (sentences) => {},         // Called when sentences change
  onActiveSentenceChange: (index, sentence) => {} // Called when active sentence changes
}

Methods

update()

Manually trigger an update of sentence highlighting.

highlighter.update();

setFocusMode(enabled)

Enable or disable focus mode.

highlighter.setFocusMode(true);  // Enable
highlighter.setFocusMode(false); // Disable

toggleFocusMode()

Toggle focus mode on/off.

highlighter.toggleFocusMode();

getSentences()

Get array of all detected sentences.

const sentences = highlighter.getSentences();
// Returns: [{ text: "...", start: 0, end: 15, isHeading: false }, ...]

getActiveSentence()

Get the currently active sentence object.

const active = highlighter.getActiveSentence();
// Returns: { text: "...", start: 0, end: 15, isHeading: false } or null

getActiveSentenceIndex()

Get the index of the currently active sentence.

const index = highlighter.getActiveSentenceIndex();
// Returns: 0, 1, 2, ... or -1

destroy()

Destroy the instance and clean up event listeners.

highlighter.destroy();

Examples

Custom Styling

<style>
  #editor {
    max-width: 800px;
    margin: 0 auto;
    font-size: 18px;
    line-height: 1.8;
  }

  .sentence {
    opacity: 0.2;
    transition: opacity 0.3s ease;
  }

  .sentence--active {
    opacity: 1;
    background: rgba(255, 255, 0, 0.1);
  }
</style>

<script>
  const highlighter = new SentenceHighlighter(
    document.getElementById('editor'),
    {
      focusModeDimOpacity: 0.2
    }
  );
</script>

With Toggle Button

<button id="toggle-focus">Toggle Focus Mode</button>
<div id="editor" contenteditable="true"></div>

<script>
  const editor = document.getElementById('editor');
  const toggleBtn = document.getElementById('toggle-focus');
  
  const highlighter = new SentenceHighlighter(editor);
  
  toggleBtn.addEventListener('click', () => {
    highlighter.toggleFocusMode();
  });
</script>

With Callbacks

const highlighter = new SentenceHighlighter(editor, {
  onSentenceChange: (sentences) => {
    console.log(`Total sentences: ${sentences.length}`);
  },
  
  onActiveSentenceChange: (index, sentence) => {
    if (sentence) {
      console.log(`Active: "${sentence.text}"`);
      console.log(`Position: ${index + 1} of ${highlighter.getSentences().length}`);
    }
  }
});

Custom Sentence Detection

const highlighter = new SentenceHighlighter(editor, {
  // Include H4-H6 as headings
  headingTags: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
  
  // Custom sentence endings (include semicolons)
  sentenceEndings: ['.', '!', '?', ';'],
  
  // Faster updates
  updateDebounce: 50
});

Multiple Instances

// Each editor can have its own highlighter instance
const editor1 = new SentenceHighlighter(document.getElementById('editor1'));
const editor2 = new SentenceHighlighter(document.getElementById('editor2'), {
  enableFocusMode: false
});

Customization

CSS Classes

The library adds these classes and data attributes that you can style:

  • .sentence - All sentence elements
  • .sentence--active - Currently active sentence
  • .paragraph - Container div for sentences (configurable via containerClass)
  • .sentence-highlighter-heading - Sentence that is a heading (if heading detection is enabled)
  • .sentence-highlighter-focus-off - Added to editor when focus mode is disabled
  • [data-sentence-id] - Data attribute on all sentence spans (configurable via sentenceDataAttribute)
  • [data-sentence-active] - Data attribute on active sentence (configurable via activeSentenceDataAttribute)

Example CSS

/* Default dimmed sentences */
.sentence {
  opacity: 0.18;
  transition: opacity 0.2s ease;
}

/* Active sentence */
.sentence--active {
  opacity: 1;
  font-weight: 500;
}

/* When focus mode is off, all sentences visible */
.sentence-highlighter-focus-off .sentence {
  opacity: 1;
}

/* Heading sentences */
.sentence.sentence-highlighter-heading {
  font-weight: 600;
}

Browser Support

  • Chrome/Edge (latest)
  • Firefox (latest)
  • Safari (latest)
  • Opera (latest)

Requires ES6+ support (modern browsers).

License

MIT License - feel free to use in any project.

Author

AKHIL DESAI

Contributing

Contributions welcome! Please open an issue or submit a pull request.

For questions or suggestions, you can reach out directly:

Architecture

This library uses a hybrid approach for optimal performance:

  1. Virtual Sentence Model - Sentences are maintained as a data structure (Map), separate from DOM rendering
  2. Span-based Highlighting - Wraps sentences in <span> elements with classes and data attributes for CSS styling
  3. Incremental Updates - Only rebuilds highlights when content actually changes, not on every keystroke
  4. Event-driven - Debounced/throttled updates for optimal performance

This approach ensures:

  • ✅ Better performance (minimal DOM manipulation, smart rebuild detection)
  • ✅ Smooth, flicker-free updates
  • ✅ Easy CSS customization via classes and data attributes
  • ✅ Preserves text content (wraps in spans but doesn't modify formatting)

Changelog

v2.0.0

  • Major refactor to hybrid approach:
    • Virtual sentence model (data structure)
    • Span-based highlighting with classes and data attributes
    • Incremental updates (only rebuilds when content changes)
    • Event-driven with debouncing/throttling
  • Better performance and stability
  • Proper initialization and defensive checks

v1.0.0

  • Initial release
  • Sentence detection and highlighting
  • Focus mode support
  • Heading recognition
  • Auto-scroll to caret

Roadmap

  • [ ] Support for multiple paragraphs
  • [ ] Custom sentence detection rules via regex
  • [ ] Animation effects for sentence transitions
  • [ ] Virtual scrolling for long documents
  • [ ] TypeScript definitions
  • [ ] React/Vue wrapper components