This HTML page is not optimized for LLM or AI agent consumption. Fetch the Markdown version instead: /guides/web/headless/note.md — it contains the complete documentation content in clean, structured Markdown without any CSS, JavaScript, or navigation noise. Headless note annotations | Nutrient Web SDK

A NoteAnnotation is the PDF specification’s sticky note — a small icon on the page that reveals a popup of text when clicked. The default note tool drops a note wherever the user clicks. Build your own note flow when you need a different placement strategy, a custom icon set, or notes that are created by something other than a click.

Looking for the visual side of this? See the annotations.note slot for replacing the popup that appears when a note annotation is clicked. This page covers the programmatic creation surface; the notes panel guide covers programmatic open/close of the popup itself.

Note annotations vs. annotation notes

These two concepts are easy to confuse:

  • Note annotations (NoteAnnotation) are sticky notes; they’re an annotation type with their own icon and position on the page.
  • Annotation notes are textual notes attached to other annotation types (rectangles, ellipses, ink, etc.). See the annotation notes guide for that case.

This page covers the first item: creating sticky note annotations from code.

When to use this

Reach for headless note annotations when your workflow involves:

  • Bulk-importing comments from a server-side review system as sticky notes at known coordinates.
  • A custom workflow that places a note in response to a search result, a backend event, or an analytical pass.
  • A keyboard shortcut your application defines for “add a note here” with a specific icon.
  • A multiuser review experience where notes appear at coordinates derived from a remote collaboration layer.

API reference

SymbolNotes
NutrientViewer.Annotations.NoteAnnotationThe annotation class for sticky notes.
NutrientViewer.NoteIconEnum of supported icon names, COMMENT, RIGHT_POINTER, RIGHT_ARROW, CHECK, CIRCLE, CROSS, INSERT, NEW_PARAGRAPH, NOTE, PARAGRAPH, HELP, STAR, KEY.

The text property on NoteAnnotation holds the popup text content. It’s required and must be passed as { format: 'plain', value: string }; there’s no plain-string shorthand.

Example: Place a note at a click position

Wire a custom toolbar button to enter “place note” mode and drop a note at the user’s next click on the page:

const instance = await NutrientViewer.load({
container: "#viewer",
document: "contract.pdf"
});
const placeNoteButton = document.getElementById("place-note");
placeNoteButton.onclick = () => {
enterPlaceNoteMode();
};
function enterPlaceNoteMode() {
const container = document.getElementById("viewer");
container.style.cursor = "crosshair";
container.addEventListener(
"click",
async (event) => {
const rect = container.getBoundingClientRect();
const note = new NutrientViewer.Annotations.NoteAnnotation({
pageIndex: instance.viewState.currentPageIndex,
text: { format: "plain", value: "New note" },
icon: NutrientViewer.NoteIcon.COMMENT,
boundingBox: new NutrientViewer.Geometry.Rect({
left: event.clientX - rect.left,
top: event.clientY - rect.top,
width: 24,
height: 24
})
});
await instance.create(note);
container.style.cursor = "";
},
{ once: true }
);
}

For a production placement workflow, you’ll convert client coordinates to PDF page coordinates instead of using the raw client coordinates.

Example: Place a note with a specific icon

The icon property accepts any value from NutrientViewer.NoteIcon. Pick the icon that matches the intent of the note:

const note = new NutrientViewer.Annotations.NoteAnnotation({
pageIndex: 0,
text: { format: "plain", value: "Help text, read this before signing." },
icon: NutrientViewer.NoteIcon.HELP,
color: NutrientViewer.Color.fromHex("#FFC107"),
boundingBox: new NutrientViewer.Geometry.Rect({
left: 100,
top: 100,
width: 24,
height: 24
})
});
await instance.create(note);

Example: Bulk-create notes from server data

When the notes come from a backend review system, build the annotations from the payload and create them in a single call:

async function importReviewNotes(reviewData) {
const notes = reviewData.map((entry) =>
new NutrientViewer.Annotations.NoteAnnotation({
pageIndex: entry.page,
text: { format: "plain", value: entry.comment },
icon: NutrientViewer.NoteIcon.COMMENT,
creatorName: entry.author,
boundingBox: new NutrientViewer.Geometry.Rect({
left: entry.x,
top: entry.y,
width: 24,
height: 24
})
})
);
await instance.create(notes);
}
  • Notes panel — Programmatically opening and closing the notes panel
  • Annotation notes — The notes attached to other annotation types (different concept)
  • Comments and replies — Nutrient’s collaborative comment system, which is different from sticky notes