A JavaScript library for adding interactive text annotation functionality to web applications.
Also available: React wrapper | TEI/XML extension | Recogito PDF Annotator
npm install @recogito/text-annotatorimport { createTextAnnotator } from '@recogito/text-annotator';
const anno = createTextAnnotator(document.getElementById('content'));
// Load annotations from a file
anno.loadAnnotations('annotations.json');
// Listen to user events
anno.on('createAnnotation', annotation => {
  console.log('new annotation', annotation);
});     const anno = createTextAnnotator(element, options);| Option | Type | Default | Description | 
|---|---|---|---|
| annotatingEnabled | boolean | true | Enable or disable interactive creation of new annotations. | 
| dismissOnNotAnnotatable | 'NEVER' | 'ALWAYS' | function | 'NEVER' | Controls whether the current selection is dismissed when clicking outside of annotatable content. | 
| selectionMode | 'shortest' | 'all' | 'shortest' | When the user selects overlapping annotations: select all or only the shortest. | 
| style | HighlightStyleExpression | undefined | Custom styling function for highlights. | 
| user | User | anonymous guest | Current user information, automatically added to created or updated annotations. | 
Returns all annotations.
const annotations = anno.getAnnotations();Returns the annotations with the given ID.
const annotation = anno.getAnnotationById('annotation-id');Bulk-adds annotations. If replace is true (default), all existing annotations are removed first. If false, the new annotations are appended to existing ones.
anno.setAnnotations(annotations);Loads annotations from a URL.
await anno.loadAnnotations('/annotations.json');Adds a single annotation programmatically.
anno.addAnnotation(annotation);Updates an existing annotation. (The original annotation with the same ID will be replaced.)
anno.updateAnnotation(updated);Removes an annotation by object or ID.
anno.removeAnnotation('annotation-id');Removes all annotations.
anno.clearAnnotations();Returns currently selected annotations.
const selected = anno.getSelected();Programmatically select annotation(s). Passing undefined or no argument will clear selection.
anno.setSelected('annotation-id');
anno.setSelected(['id-1', 'id-2']);Programmatically cancel the current selection.
anno.cancelSelected();Scrolls the annotation into view. Returns true if successful, false if annotation is not currently rendered.
anno.scrollIntoView('annotation-id');Returns the current user.
const user = anno.getUser();Sets the current user.
anno.setUser({ id: '[email protected]', name: 'John' });Applies a filter function to control which annotations are displayed.
anno.setFilter(annotation => 
  annotation.bodies.some(b => b.purpose === 'commenting')
);Updates the highlighting style function.
anno.setStyle(annotation => ({
  fill: annotation.bodies[0]?.purpose === 'tagging' ? 'yellow' : 'lightblue',
  fillOpacity: 0.25
}));Shows or hides all annotations.
anno.setVisible(false); Programmatically undo the last user edit.
anno.undo();Programmatically redo the last undone user edit.
anno.redo();Destroys the annotator instance and cleans up all event listeners.
anno.destroy();Listen to annotation lifecycle events using on() and remove listeners with off().
Fired when the user creates a new annotation.
// Example: save new annotations to a backend
anno.on('createAnnotation', annotation => {
  console.log('Created:', annotation);
  fetch('/my-api/annotations', {
    method: 'POST',
    body: JSON.stringify(annotation)
  });
});Fired when the user updates an annotation. Receives the updated annotation and the previous version.
anno.on('updateAnnotation', (annotation, previous) => {
  console.log('Updated:', annotation, 'was:', previous);
});Fired when the user deletes an annotation.
anno.on('deleteAnnotation', annotation => {
  console.log('Deleted:', annotation);
});Fired when the selection was changed by the user.
anno.on('selectionChanged', annotations => {
  console.log('Selected:', annotations);
});Remove event listeners:
const handler = annotation => console.log(annotation);
anno.on('createAnnotation', handler);
anno.off('createAnnotation', handler);The Text Annotator data model aligns closely with the W3C Web Annotation Data Model, but with a few key differences to optimize for performance and ease of use. Every annotation in Annotorious is represented by a JavaScript object with the following structure:
{
  "id": "67a427d7-afc3-474a-bdab-1e2ea8dc78f6",
  "bodies": [],
  "target": {
    "selector": [{
      "quote": "Tell me, O muse",
      "start": 48,
      "end": 63
    }],
    "creator": {
        "id": "zD62eVrpvJgMEEWuPpPS"
    },
    "created": "2025-09-30T07:28:54.973Z",
    "updated": "2025-09-30T07:28:56.158Z"
  }
}- 
id- a unique identifier for the annotation. The ID can be any alphanumeric string. Annotations created by users will receive a globally unique UUID automatically.
- 
target- the target represents the text range that the annotation is associated with. Theselectorprovides the selectedquoteand character offsets forstartandend.
- 
bodiesare designed to carry application-specific payload, such as comments, tags, or other metadata associated with the annotation.
You can customize the appearance of highlights using the style config option or setStyle() method.
const anno = createTextAnnotator(element, {
  style: {
    fill: '#ffeb3b',
    fillOpacity: 0.25,
    underlineStyle: 'dashed',
    underlineColor: '#7d7208ff',
    underlineOffset: 0,
    underlineThickness: 2
  }
});You can provide a function to style annotations based on their properties. The style function receives three arguments:
- annotation- the annotation object
- state- an object with- selectedand- hoveredboolean properties
- zIndex- the stacking order (useful for layering effects on overlapping annotations)
anno.setStyle((annotation, state, zIndex) => {
  const hasTag = annotation.bodies.some(b => b.purpose === 'tagging');
  
  return {
    fill: hasTag ? '#ffeb3b' : '#bbdefb',
    fillOpacity: state.hovered ? 0.35 : 0.2,
    underlineColor: hasTag ? '#f57f17' : undefined
  };
});The Recogito Text Annotator is licensed under the BSD 3-Clause license.
