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

A callout is a TextAnnotation with a leader line that points from a text box to a specific spot on the page. Callouts share the text editor surface with regular text annotations, but they have two extra properties: callout (the leader line geometry) and isFitting (which adjusts the text box size to fit the content). Build callouts programmatically when placement comes from coordinates rather than a user dragging on the page.

Looking for the visual side of this? See the tools.contextual slot for replacing the inline text/callout toolbar. This page covers the programmatic surface you’ll call from inside that custom UI.

Callouts are text annotations

Callouts don’t have their own annotation class; they’re TextAnnotation instances with the callout property set. That’s worth knowing because searching the API reference for “callout” won’t surface a dedicated class.

There are two properties that turn a text annotation into a callout.

PropertyNotes
calloutA NutrientViewer.Callout instance describing the leader line geometry with start, knee (optional), end, and cap.
isFittingWhen true, the text box auto-fits to the content size. Recommended for callouts to avoid empty space in the box.

When to use this

Reach for callout annotations when you need to:

  • Label features in an engineering drawing or schematic from a coordinate set.
  • Import annotations from a CAD or analysis tool that emits “label this point with this text” data.
  • Build a custom annotation tool in your host app that creates callouts at user-picked positions with your own styling.
  • Render a guided tour overlay that points at PDF content using callout annotations rather than HTML overlays.

Example: Create a callout pointing at a coordinate

The minimal callout is a text annotation with callout set and isFitting enabled:

const { TextAnnotation } = NutrientViewer.Annotations;
const { Callout } = NutrientViewer;
const { Rect, Point } = NutrientViewer.Geometry;
const callout = new TextAnnotation({
pageIndex: 0,
text: { format: "plain", value: "Important detail" },
fontSize: 14,
fontColor: NutrientViewer.Color.BLACK,
backgroundColor: NutrientViewer.Color.fromHex("#FFFDE7"),
isFitting: true,
boundingBox: new Rect({ left: 250, top: 100, width: 160, height: 60 }),
callout: new Callout({
start: new Point({ x: 250, y: 130 }),
knee: new Point({ x: 200, y: 200 }),
end: new Point({ x: 100, y: 250 }),
cap: NutrientViewer.LineCap.openArrow
})
});
await instance.create(callout);

The start point is where the leader leaves the text box. The end point is what the callout points at. The optional knee adds a single bend between the two; omit it for a straight leader.

Example: Convert an existing text annotation to a callout

When you already have a text annotation and want to add a leader line, set the callout property using set() (text annotations are immutable records):

const annotations = await instance.getAnnotations(0);
const target = annotations.find(
(a) => a instanceof NutrientViewer.Annotations.TextAnnotation
);
if (target) {
const updated = target
.set("isFitting", true)
.set(
"callout",
new NutrientViewer.Callout({
start: new NutrientViewer.Geometry.Point({ x: target.boundingBox.left, y: target.boundingBox.top + 20 }),
end: new NutrientViewer.Geometry.Point({ x: 50, y: 200 }),
cap: NutrientViewer.LineCap.openArrow
})
);
await instance.update(updated);
}

Example: Import callouts from a CAD-style coordinate list

When the callout positions come from a server or an external tool, map the data into TextAnnotation instances and create them in a single call:

async function importLabels(labels) {
const annotations = labels.map((label) =>
new NutrientViewer.Annotations.TextAnnotation({
pageIndex: label.page,
text: { format: "plain", value: label.text },
fontSize: 12,
isFitting: true,
backgroundColor: NutrientViewer.Color.fromHex("#FFFFFF"),
strokeColor: NutrientViewer.Color.fromHex("#1976D2"),
boundingBox: new NutrientViewer.Geometry.Rect({
left: label.boxX,
top: label.boxY,
width: 140,
height: 40
}),
callout: new NutrientViewer.Callout({
start: new NutrientViewer.Geometry.Point({ x: label.boxX, y: label.boxY + 20 }),
end: new NutrientViewer.Geometry.Point({ x: label.targetX, y: label.targetY }),
cap: NutrientViewer.LineCap.openArrow
})
})
);
await instance.create(annotations);
}