Skip to content

recogito/text-annotator-js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Recogito Text Annotator

A JavaScript library for adding interactive text annotation functionality to web applications.

Also available: React wrapper | TEI/XML extension | Recogito PDF Annotator

Animated screenshot of the Recogito Text Annotator

Installation

npm install @recogito/text-annotator

Quick Start

import { 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);
});     

Configuration Options

const anno = createTextAnnotator(element, options);
Option Type Default Description
allowModifierSelect boolean false Allows users to extend an existing annotation by holding Ctrl (Cmd on Mac) while selecting.
annotatingEnabled boolean true Enable or disable creation of new annotations.
dismissOnNotAnnotatable 'NEVER' | 'ALWAYS' | function 'NEVER' Controls whether the currently selected annotation is un-selected when clicking outside the annotatable area.
mergeHighlights object undefined Merge adjacent highlights. Options: horizontalTolerance and verticalTolerance (pixels)
selectionMode 'shortest' | 'all' 'shortest' When selecting overlapping annotations: select all or only the shortest.
style HighlightStyleExpression undefined Custom highlight styling function.
user User anonymous guest Current user info, automatically added to new or updated annotations.
userSelectAction UserSelectActionExpression SELECT Behavior when the user selects an annotation (see below)

Annotator API

Methods

addAnnotation(annotation)

Add a single annotation programmatically.

anno.addAnnotation(annotation);

cancelSelected()

Programmatically cancel the current selection.

anno.cancelSelected();

canRedo() / canUndo()

Test if there are any re- or undoable user actions in the undo stack.

const canRedo = anno.canRedo();

clearAnnotations()

Remove all annotations.

anno.clearAnnotations();

destroy()

Destroy the annotator instance and clean up all event listeners.

anno.destroy();

getAnnotationById(id)

Retrieve a specific annotation.

const annotation = anno.getAnnotationById('annotation-id');

getAnnotations()

Return all annotations.

const annotations = anno.getAnnotations();

getSelected()

Return currently selected annotations.

const selected = anno.getSelected();

getUser()

Return the current user.

const user = anno.getUser();

loadAnnotations(url, replace = true)

Load annotations from a URL.

await anno.loadAnnotations('/annotations.json');

redo() / undo()

Programmatically redo or undo the last user edit.

anno.undo();
anno.redo();

removeAnnotation(annotationOrId)

Delete an annotation by ID or object.

anno.removeAnnotation('annotation-id');

scrollIntoView(annotationOrId)

Scroll the annotation into view. Returns true if successful, false if annotation is not currently rendered.

anno.scrollIntoView('annotation-id');

setAnnotatingEnabled(enabled)

Enable or disable annotation creation.

anno.setAnnotatingEnabled(false);

setAnnotatingMode(mode)

Configure the annotation mode:

  • CREATE_NEW (default): each user selection creates a new annotation.
  • ADD_TO_CURRENT: the user selection extends the currently selected annotation's range, if any.
  • REPLACE_CURRENT: the user selection replaces the currently selected annotations' range, if any.
anno.setAnnotatingMode('ADD_TO_CURRENT');

setAnnotations(annotations, replace = true)

Bulk-add annotations. If replace is true (default), all existing annotations are deleted first. If false, the new annotations are appended to existing ones.

anno.setAnnotations(annotations);

setFilter(filter)

Apply a filter function to control which annotations are displayed.

anno.setFilter(annotation => 
  annotation.bodies.some(b => b.purpose === 'commenting')
);

setSelected(idOrIds)

Programmatically select annotation(s). Passing undefined or no argument will clear selection.

anno.setSelected('annotation-id');
anno.setSelected(['id-1', 'id-2']);

setStyle(style)

Change the highlighting style function or set a static style - see details below.

anno.setStyle({
  fill: 'yellow',
  fillOpacity: 0.25
});

anno.setStyle((annotation, state) => ({
  fill: annotation.bodies[0]?.purpose === 'tagging' ? 'yellow' : 'lightblue',
  fillOpacity: state.hovered ? 0.5 : 0.25
}));

setUser(user)

Set the current user.

anno.setUser({ id: '[email protected]', name: 'John' });

setUserSelectAction(action)

Change the current userSelectAction, which determines what happens when the user selects an annotation interactively. Can be a UserSelectAction, or a function that receives the annotation as input and returns a UserSelectAction.

  • SELECT (default): The annotation will be selected and the selectionChanged event will be triggered.
  • NONE: the annotation is inert, clicking has no effect.
anno.setUserSelectAction('NONE');
anno.setUserSelectAction(annotation => annotation.bodies.length > 0 ? 'SELECT' : 'NONE');

setVisible(visible)

Show or hide all annotations.

anno.setVisible(false); 

updateAnnotation(updated)

Update an existing annotation.

anno.updateAnnotation(updated);

Events

Listen to annotation lifecycle events using on() and remove listeners with off().

createAnnotation

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)
  });
});

updateAnnotation

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);
});

deleteAnnotation

Fired when the user deletes an annotation.

anno.on('deleteAnnotation', annotation => {
  console.log('Deleted:', annotation);
});

selectionChanged

Fired when the selection was changed by the user.

anno.on('selectionChanged', annotations => {
  console.log('Selected:', annotations);
});

viewportIntersect

Fired when annotations enter or leave the visible area.

anno.on('viewportIntersect', annotations => {
  console.log('Visible:', annotations);
});

Remove event listeners:

const handler = annotation => console.log(annotation);
anno.on('createAnnotation', handler);
anno.off('createAnnotation', handler);

Annotation Data Model

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. The selector provides the selected quote and character offsets for start and end.

  • bodies are designed to carry application-specific payload, such as comments, tags, or other metadata associated with the annotation.

Annotation Styling

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 selected and hovered boolean 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
  };
});

License

The Recogito Text Annotator is licensed under the BSD 3-Clause license.

About

A JavaScript library for text annotation.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •