Hooks
Hooks for headless annotation usage and custom components.
useAnnotatable
Access annotation context inside Document.Annotatable. Use this to build custom annotation UI.
import { useAnnotatable } from "@tilt-legal/cubitt-components/document";
function CustomButton() {
const { createAnnotation, annotations } = useAnnotatable();
return (
<button onClick={() => createAnnotation()}>
Add ({annotations.length})
</button>
);
}Returns
| Property | Type | Description |
|---|---|---|
annotations | AnnotationData[] | Current annotations |
activeAnnotationId | string | null | Selected annotation |
hoveredAnnotationId | string | null | Hovered annotation |
createAnnotation | (initialText?: string) => void | Create annotation from selection |
createAnnotationFromMarkdownText | (citedText: string, comment: string, options?: { instance?: number; author?: AnnotationAuthor }) => AnnotationData | null | Create annotation from markdown text. instance (1-indexed, default 1) specifies which occurrence when text appears multiple times. author overrides defaultAuthor for this annotation. Returns null if text not found. |
updateAnnotation | (id: string, text: string) => void | Update annotation text |
deleteAnnotation | (id: string) => void | Delete annotation |
setActiveAnnotation | (id: string | null) => void | Set active annotation |
setHoveredAnnotation | (id: string | null) => void | Set hovered annotation |
scrollToAnnotation | (id: string) => void | Scroll to annotation in document |
selectNextAnnotation | () => void | Navigate to next annotation |
selectPreviousAnnotation | () => void | Navigate to previous annotation |
getAnnotationsWithPositions | () => AnnotationData[] | Get annotations sorted by position |
getAnnotationById | (id: string) => AnnotationData | undefined | Find annotation by ID |
getMarkdown | () => string | Get document as markdown |
applyAnnotationMark | (id: string) => void | Apply annotation mark to editor |
removeAnnotationMark | (id: string) => void | Remove annotation mark from editor |
useAnnotationCard
Access per-card state inside Document.Annotation.Sidebar.Card. Use this to build custom card components.
import { useAnnotationCard } from "@tilt-legal/cubitt-components/document";
function CustomDelete() {
const { remove, annotation, isActive } = useAnnotationCard();
return (
<button onClick={remove} disabled={!isActive}>
Delete "{annotation.citedText.slice(0, 20)}..."
</button>
);
}Returns
| Property | Type | Description |
|---|---|---|
annotation | AnnotationData | The annotation data |
isActive | boolean | Whether this card is selected |
isHovered | boolean | Whether this card is hovered |
activate | () => void | Select this annotation |
selectText | () => void | Select the annotation text in editor |
scrollToMark | () => void | Scroll to the mark in the document |
update | (text: string) => void | Update the annotation text |
remove | () => void | Delete the annotation |
useHasSelection
Boolean indicating if valid text is selected in the document. Useful for enabling/disabling add buttons.
import {
useAnnotatable,
useHasSelection,
} from "@tilt-legal/cubitt-components/document";
function HeaderAddButton() {
const hasSelection = useHasSelection();
const { createAnnotation } = useAnnotatable();
return (
<button disabled={!hasSelection} onClick={() => createAnnotation()}>
Add Annotation
</button>
);
}Returns
boolean - true when valid text is selected.
LLM Integration
When integrating with LLMs, you can have the model analyze document content and return citations that automatically become annotations. The LLM works with markdown text and doesn't need to know about editor positions.
- Export: Call
getMarkdown()to get the document content - Analyze: Send markdown to your LLM with citation requirements
- Annotate: Pass LLM citations to
createAnnotationFromMarkdownText()
Structured Output Schema
Define a schema for LLM citations:
import {
z } from "zod";
const citationSchema = z.object({
citedText: z.object({
text: z.string(),
instance: z.number(),
}),
comment: z.string(),
});Then consume it:
import { useAnnotatable } from "@tilt-legal/cubitt-components/document";
const { createAnnotationFromMarkdownText } = useAnnotatable();
for (const { citedText, comment } of citations) {
createAnnotationFromMarkdownText(citedText.text, comment, {
instance: citedText.instance,
});
}LLM System Prompt
Include citation requirements in your system prompt:
## Citation Requirements
For EVERY issue you identify, you MUST provide:
- `citedText.text`: The exact quoted text from the document
- `citedText.instance`: Which occurrence of this text (1 = first, 2 = second, etc.)
Guidelines:
- Quote the exact text, do not paraphrase
- Keep citations concise but complete enough to identify the issue
- If an issue spans multiple sentences, quote the most relevant portion
- Always specify the instance, even if the text only appears once (use 1)