0
Files
app/viewer/page.tsx
"use client";

import dynamic from "next/dynamic";

// embedpdf's plugin packages and the PDFium worker are browser-only, so the
// whole app is loaded client-side behind an `ssr: false` boundary.
const PdfViewerApp = dynamic(
  () =>
    import("@/components/pdf-viewer-app").then(
      (mod) => mod.PdfViewerApp,
    ),
  {
    ssr: false,
    loading: () => <div className="bg-muted h-full w-full" />,
  },
);

export default function Page() {
  return (
    // The viewer fills its container and scrolls inside itself, so pin an
    // explicit height here rather than letting the document grow the page.
    <div className="h-svh w-full overflow-hidden">
      <PdfViewerApp documents={[{ url: "/sample.pdf" }]} />
    </div>
  );
}

The layout — a toolbar over a collapsible left rail that switches between thumbnails, an outline, annotations, and attachments, beside the page canvas, with a style inspector and comment threads on the right — follows PDFSlick's reference app. It reads first and annotates second: the tools sit in the toolbar, and the panels open on demand.