Rasterex APINPM Package/docs/getting-started/react-quick-start

React Quick Start

Create a React viewer host, open a document, and enable a text annotation with the NPM SDK.

1. Create A React Project

Create a TypeScript React application, then start from this minimal structure.

bash
npm create vite@latest rasterex-react -- --template react-ts
cd rasterex-react
1. Create A React Project

Folder Structure

Keep the viewer lifecycle in the component that owns the viewer region.

text
rasterex-react/
├── src/
│   ├── App.tsx     # Creates, subscribes to, and destroys the viewer.
│   ├── App.css     # Gives the viewer host a stable, non-zero height.
│   └── main.tsx    # Mounts the React application.
└── package.json    # Declares React and @rasterex/viewer.
Folder Structure

2. Install The Viewer

Install the Viewer package in the new project. The document URL in the next step must be reachable by the Canvas environment.

bash
npm install @rasterex/viewer
2. Install The Viewer

3. Initialize And Open A Document

Use a ref for the host element. Register document listeners before startup, await mount() and ready(), then open the document. The cleanup function unsubscribes and destroys the viewer when React removes this component.

import { useEffect, useRef, useState } from "react";
import { createViewer, type RasterexViewer } from "@rasterex/viewer";
import "./App.css";

const FILE_URL = "https://files.example.com/sample.pdf"; // Replace with a Canvas-reachable document URL.

export default function App() {
  const hostRef = useRef<HTMLDivElement | null>(null);
  const viewerRef = useRef<RasterexViewer | null>(null);
  const [ready, setReady] = useState(false);
  const [status, setStatus] = useState("Starting viewer");

  useEffect(() => {
    if (!hostRef.current) return;

    let disposed = false;
    const viewer = createViewer({ container: hostRef.current });
    viewerRef.current = viewer;

    // Subscribe before opening so the host can reflect the document lifecycle.
    const stopOpened = viewer.documents.on("opened", () => {
      if (!disposed) {
        setReady(true);
        setStatus("Document opened");
      }
    });
    const stopFailed = viewer.documents.on("failed", (event) => {
      if (!disposed) setStatus(`Open failed: ${event.error.message}`);
    });

    async function start() {
      await viewer.mount();
      await viewer.ready();
      if (disposed) return;

      setStatus("Opening document");
      await viewer.documents.open({
        url: FILE_URL,
        displayName: "sample.pdf",
      });
    }

    void start().catch((error) => {
      if (!disposed) setStatus(error instanceof Error ? error.message : "Viewer failed");
    });

    return () => {
      disposed = true;
      stopOpened();
      stopFailed();
      viewer.destroy();
      viewerRef.current = null;
    };
  }, []);

  return (
    <main className="app-shell">
      <p role="status">{status}</p>
      <div ref={hostRef} className="viewer-host" />
      <p>{ready ? "Annotation controls are available below." : "Wait for the document to open."}</p>
    </main>
  );
}
3. Initialize And Open A Document

4. Work With Annotations

The example enables the verified TEXT annotation action after the document has opened. It clears the host tool state when the documented created event arrives.

Creating an annotation is not a persistence confirmation. When the host must save changes, use the result-backed save flow documented in Annotation API and Save annotations.

tsx
async function enableTextAnnotation() {
  const viewer = viewerRef.current;
  if (!viewer || !ready) return;

  const result = await viewer.tools.set({
    action: "TEXT",
    enabled: true,
  });

  setStatus(result.success ? "Text tool active" : (result.error ?? "Text tool failed"));
}

// Register this in the same effect as the other subscriptions.
const stopCreated = viewer.annotations.on("created", (event) => {
  if (!disposed) setStatus(`Created annotation ${event.guid}`);
});

// Add an accessible control to the component.
<button type="button" disabled={!ready} onClick={() => void enableTextAnnotation()}>
  Add text annotation
</button>

// Call stopCreated() in the effect cleanup before viewer.destroy().
4. Work With Annotations