A framework-agnostic TypeScript library for anchoring and highlighting text in web documents with intelligent fallback strategies.
- 🎯 Multiple anchoring strategies with automatic fallback
- 📝 Text highlighting with customizable styles
- 🌐 Framework-agnostic - works with any JavaScript framework
- 🔧 TypeScript support with full type definitions
- 📱 PDF document support for complex layouts
- ⚡ Event-driven architecture for reactive applications
- 🎨 Context-aware filtering for multi-document apps
npm install @net7/annotator
# or
yarn add @net7/annotator
import { Annotator } from '@net7/annotator';
// Create annotator instance
const annotator = new Annotator();
// Set document context
annotator.setContext({ documentId: 'doc-123' });
// Create annotation from user selection
const selection = window.getSelection();
if (selection && selection.rangeCount > 0) {
const result = annotator.createAnnotation({
root: document.body,
range: selection.getRangeAt(0),
context: { documentId: 'doc-123' },
color: '#FFFF00',
metadata: { comment: 'Important note' },
});
console.log('Annotation created:', result);
}
new Annotator(options?: { allowWhitespace?: boolean })
Method | Description |
---|---|
setContext(context) |
Set document context for filtering |
createAnnotation(params) |
Create annotation from DOM range |
load(annotations, root) |
Load multiple annotations |
remove(annotationId) |
Remove annotation by ID |
getEvents() |
Get event emitter for highlight events |
// Listen to highlight events
annotator.getEvents().on('highlight', (event) => {
console.log('Highlight event:', event.type, event.payload);
});
The library uses a smart anchoring system with automatic fallback:
- RangeSelector (Most precise) - DOM node references
- TextPositionSelector (Reliable) - Character offsets
- TextQuoteSelector (Robust) - Text content matching
When one strategy fails, it automatically tries the next one, ensuring maximum reliability across different document states.
// Load existing annotations
const annotations = await fetchAnnotations();
annotator.load(annotations, document.body);
// Context-aware filtering
annotator.setContext({
documentId: 'doc-123',
pageNumber: 5,
userId: 'user-456',
});
const annotator = new Annotator({ allowWhitespace: true });
annotator.getEvents().on('highlight', (event) => {
if (event.type === 'click') {
showAnnotationDetails(event.payload);
}
});
We welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Write tests for your changes
- Ensure all tests pass (
npm test
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
# Install dependencies
npm install
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Build library
npm run build
# Lint code
npm run lint
Check out the docs/
directory for:
- Basic usage examples
- Advanced demo with full UI
- TypeScript integration examples
This project is licensed under the BSD-2-Clause License - see the LICENSE file for details.
This library incorporates code from:
- Hypothesis Client (BSD-2-Clause)
- dom-anchor-text-quote (MIT)
- dom-anchor-text-position (MIT)
See NOTICE for complete attribution details.