@lorb/ghost-highlight
v0.1.1
Published
Highlight text without touching the DOM. Full CSS control, animations, live updates
Maintainers
Readme
@lorb/ghost-highlight
Highlight text without touching the DOM.
Zero DOM mutation. Uses the Custom Highlight API — highlights are a rendering layer, not DOM nodes. No wrappers, no broken selectors, no killed event handlers.
Full CSS control. Background color, text color, underlines, text shadows, custom animations — anything CSS ::highlight() supports.
Live. Highlights follow DOM changes automatically. Content updates? Highlights re-apply on their own.
import { search } from '@lorb/ghost-highlight';
search('keyword');
// Every instance of "keyword" on the page is now highlighted.
// The DOM is untouched.Install
npm install @lorb/ghost-highlightWhat you can do
Search and highlight text
import { search, clear } from '@lorb/ghost-highlight';
search('error'); // highlight all matches
search('warning', { // with custom color
style: { backgroundColor: 'rgba(255, 200, 0, 0.3)' },
});
clear(); // remove all highlightsStyle highlights with full CSS
Beyond background color — use text color, underlines, text shadows, and decorations.
search('deprecated', {
style: {
backgroundColor: 'rgba(255, 0, 0, 0.1)',
color: '#ff4444',
textDecoration: 'line-through red',
},
});
search('important', {
style: {
textShadow: '0 0 8px gold',
backgroundColor: 'rgba(255, 215, 0, 0.2)',
},
});Animate highlights
Three built-in animation presets, or define your own keyframes.
// Built-in presets: fade-in, pulse, sweep
search('new', {
style: {
backgroundColor: 'gold',
animation: { preset: 'pulse', iterations: 3 },
},
});
// Custom keyframes — anything CSS animation supports
search('alert', {
style: {
animation: {
keyframes: '@keyframes glow { 0% { background-color: transparent } 50% { background-color: red } 100% { background-color: transparent } }',
duration: '1s',
easing: 'ease-in-out',
iterations: 'infinite',
},
},
});Multiple highlight groups that overlap
Different groups stack visually. Priority controls which renders on top.
import { search, createGroup, clear } from '@lorb/ghost-highlight';
// Built-in presets with priority levels
search('error message', { preset: 'error' }); // priority 2 (top)
search('network', { preset: 'warning' }); // priority 1
search('response', { preset: 'info' }); // priority 0 (bottom)
clear('error'); // clear one group
clear(); // clear allHighlight specific ranges
For precise control — highlight exact positions, not just text matches.
import { highlight } from '@lorb/ghost-highlight';
const range = new Range();
range.setStart(textNode, 10);
range.setEnd(textNode, 25);
highlight(range, 'selection', {
backgroundColor: 'rgba(0, 120, 255, 0.3)',
});Live-update when content changes
Highlights automatically re-apply when the DOM mutates.
import { search, observe } from '@lorb/ghost-highlight';
observe(); // start watching
search('keyword'); // highlights persist through content updates
// Dynamic content? SPA navigation? Editor changes?
// Highlights follow automatically.Check what's highlighted at a position
import { getGroupsAt } from '@lorb/ghost-highlight';
const groups = getGroupsAt(textNode, 5);
// Returns array of group names at that cursor position
// Useful for context menus, inspectors, or tooltipsBrowser support
Uses the Custom Highlight API — zero DOM mutation. Supported in Chrome 105+, Edge 105+, Safari 17.2+, Firefox 132+.
In older browsers, falls back to <span> wrapping (DOM mutation, with a console warning). Use isSupported() to check which mode is active.
API
| Export | Description |
|--------|-------------|
| search(query, options?) | Highlight all text matches. Returns match count |
| highlight(range, group?, style?) | Highlight a specific Range |
| clear(group?) | Clear one or all groups |
| createGroup(name, options?) | Pre-configure a highlight group with styles and priority |
| observe(root?, debounceMs?) | Auto-update highlights on DOM changes |
| getGroupsAt(node, offset) | Query which groups exist at a position |
| isSupported() | Check for Custom Highlight API support |
Built-in presets: search, error, warning, info, selection
Animation presets: fade-in, pulse, sweep
License
𖦹 MIT — Lorb.studio
