React Quick Start
Build your first annotation viewer with Annota and React.
Prerequisites
Section titled “Prerequisites”- React 18+ or 19+ installed
- Annota package installed (see Installation)
- Basic knowledge of React hooks
Minimal Example
Section titled “Minimal Example”Here’s the simplest possible annotation viewer:
import { AnnotaProvider, AnnotaViewer, Annotator } from "annota";import { useState } from "react";import "annota/dist/index.css";
function App() { const [viewer, setViewer] = useState(null);
return ( <AnnotaProvider slideId="my-slide"> <div style={{ width: "100vw", height: "100vh" }}> <AnnotaViewer options={{ tileSources: "/path/to/image.dzi", prefixUrl: "https://cdn.jsdelivr.net/npm/openseadragon@4/build/openseadragon/images/", }} onViewerReady={setViewer} /> <Annotator viewer={viewer} /> </div> </AnnotaProvider> );}
export default App;That’s it! You now have a working image viewer with annotation capabilities.
Understanding the Code
Section titled “Understanding the Code”1. AnnotaProvider
Section titled “1. AnnotaProvider”<AnnotaProvider slideId="my-slide">Wraps your application and provides React context for annotations. The slideId identifies this slide’s annotations.
2. AnnotaViewer
Section titled “2. AnnotaViewer”<AnnotaViewer options={{ tileSources: "/path/to/image.dzi", prefixUrl: "...", }} onViewerReady={setViewer}/>Creates the OpenSeadragon viewer instance. Returns the viewer via onViewerReady callback.
3. Annotator
Section titled “3. Annotator”<Annotator viewer={viewer} />Creates the annotation overlay layer. Requires the viewer instance.
Adding Annotation Tools
Section titled “Adding Annotation Tools”Let’s add tools for creating annotations:
import { AnnotaProvider, AnnotaViewer, Annotator, useTool } from "annota";import { PointTool, RectangleTool, PolygonTool } from "annota";import { useState } from "react";
function App() { const [viewer, setViewer] = useState(null); const [tool, setTool] = useState("point");
return ( <AnnotaProvider slideId="my-slide"> <div style={{ width: "100vw", height: "100vh" }}> <Toolbar tool={tool} onToolChange={setTool} />
<AnnotaViewer options={{ tileSources: "/path/to/image.dzi", prefixUrl: "https://cdn.jsdelivr.net/npm/openseadragon@4/build/openseadragon/images/", }} onViewerReady={setViewer} />
<Annotator viewer={viewer}> <ToolController viewer={viewer} tool={tool} /> </Annotator> </div> </AnnotaProvider> );}
function Toolbar({ tool, onToolChange }) { return ( <div style={{ position: "absolute", top: 20, left: 20, zIndex: 10 }}> <button onClick={() => onToolChange("point")}>Point</button> <button onClick={() => onToolChange("rectangle")}>Rectangle</button> <button onClick={() => onToolChange("polygon")}>Polygon</button> <button onClick={() => onToolChange("pan")}>Pan</button> </div> );}
function ToolController({ viewer, tool }) { const tools = { point: new PointTool(), rectangle: new RectangleTool(), polygon: new PolygonTool(), };
useTool({ viewer, handler: tool === "pan" ? null : tools[tool], enabled: tool !== "pan", });
return null;}Accessing Annotations with Hooks
Section titled “Accessing Annotations with Hooks”Use React hooks to access annotations reactively:
import { useAnnotations, useSelection } from "annota";
function AnnotationList() { const annotations = useAnnotations(); const selection = useSelection();
return ( <div style={{ position: "absolute", top: 20, right: 20, zIndex: 10 }}> <h3>Annotations ({annotations.length})</h3> <ul> {annotations.map((ann) => ( <li key={ann.id}> {ann.shape.type} {selection.some((s) => s.id === ann.id) && " (selected)"} </li> ))} </ul> </div> );}Common React Patterns
Section titled “Common React Patterns”Loading Existing Annotations
Section titled “Loading Existing Annotations”import { useAnnotator } from "annota";import { useEffect } from "react";
function LoadAnnotations() { const annotator = useAnnotator();
useEffect(() => { if (!annotator) return;
fetch("/api/annotations/slide-001") .then((res) => res.json()) .then((annotations) => { annotator.addAnnotations(annotations); }); }, [annotator]);
return null;}Saving Annotations
Section titled “Saving Annotations”import { useAnnotations } from "annota";
function SaveButton() { const annotations = useAnnotations();
const handleSave = () => { fetch("/api/annotations/slide-001", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(annotations), }); };
return <button onClick={handleSave}>Save</button>;}Custom Styling
Section titled “Custom Styling”<Annotator viewer={viewer} style={(annotation) => ({ fill: annotation.properties?.type === "tumor" ? "#FF0000" : "#00FF00", fillOpacity: 0.3, stroke: "#FFFFFF", strokeWidth: 2, })}/>Next Steps
Section titled “Next Steps”Now that you have a working React annotation viewer:
- Core Concepts — Understand annotations, layers, and tools
- React Hooks API — Learn about all React hooks
- Annotation Tools — Learn about all available tools
- Layer System — Organize annotations into layers
- Events — Respond to annotation changes
Want to try Svelte instead? See the Svelte Quick Start