Skip to main content
This tutorial continues the notes app from Document creation: users can author notes, and now you add a clean read view — the document displayed without a toolbar or editing chrome — plus a public share view. Reading uses <QirtaasRenderer> instead of the editor. The renderer’s auth is per read, and which credential you use depends on who is reading:
ReaderAuthCovered in
The document’s authorgetToken (same embed token as the editor)this tutorial
Anyone with the linkshareTokenthis tutorial
Another signed-in user, gated by your ACLgetSignatureAccess control
The first two need no backend change at all — the token endpoint from the creation tutorial already covers own-document reads, and share tokens carry their own authorization.

1. Frontend — the read view

Mount <QirtaasRenderer> with the same getToken the editor uses. An embed token authorizes reads of that identity’s own documents, so this works for the author viewing any note from their listDocuments() list:
src/ReadNote.tsx
import { QirtaasRenderer } from "@qirtaas/react";
import { getToken } from "./qirtaas";

export function ReadNote({ docId }: { docId: string }) {
  return (
    <QirtaasRenderer
      key={docId} // renderer props aren't live — remount per document
      documentId={docId}
      getToken={getToken}
      locale="ar"
      theme="light"
      onError={(code) => console.error("render failed:", code)}
    />
  );
}
Unlike the editor, the renderer sizes to its content — no bounded-height container required.
Mount one Qirtaas embed at a time when their connections differ — the SDK’s HTTP transport is shared per page, so a second renderer with a different auth source takes over the connection from the first. For the note list, keep rendering plain listDocuments() data and mount the renderer only on the detail page. See Client.

2. Frontend — switch between reading and editing

A common pattern is a read view with an “Edit” button for the owner. Because read and edit are different mounts, just swap components:
export function NotePage({ docId }: { docId: string }) {
  const [editing, setEditing] = useState(false);

  return editing ? (
    <EditNote docId={docId} />   // <QirtaasEditor> from the creation tutorial
  ) : (
    <>
      <button onClick={() => setEditing(true)}>Edit</button>
      <ReadNote docId={docId} />
    </>
  );
}
Both mounts use the same embed token, so they can coexist with a plain swap — each component destroys its embed on unmount.

3. Public reads with a share token

A document explicitly shared by its author carries an opaque share token that resolves it publicly — no key, no signature, no login. If your app stores a note’s share token, a public page is one prop:
src/SharedNote.tsx
import { QirtaasRenderer } from "@qirtaas/react";

export function SharedNote({ shareToken }: { shareToken: string }) {
  // No documentId needed — the token resolves the document.
  return <QirtaasRenderer shareToken={shareToken} locale="ar" theme="light" />;
}
Anyone holding the token can read the document, so treat it like any capability URL: only surface it through an explicit “share” action.

Where you are

Authors can read their own notes cleanly and share individual documents with the world — still on a single backend endpoint. The remaining case — other signed-in users reading a document when your app decides who’s allowed — needs neither of these credentials, and it’s where your backend re-enters the picture:

Access control with signatures

Gate cross-user reads behind your own ACL with per-document HMAC signatures.