Skip to content
React Web PDF Editor

react-web-pdf-editor

Edit PDFs in Next.js

This demo opens the same sample PDF three ways: a direct client import, a browser-only dynamic import, and a toolbar you render yourself. Each section below links to the live page and shows the code to create that example in your own app.

Examples

All three routes load /file/compressed.tracemonkey-pldi-09.pdf. Replace that URL with your own PDF when you copy the code.

Example 01

Quick start

A client component that imports PdfEditor, loads the stylesheet, and opens a PDF with a document name and a full-viewport height.

  • Direct import of PdfEditor from react-web-pdf-editor
  • Stylesheet import required for toolbar and page layout
  • file, name, and style props

components/quick-start.tsx

Open quick start

Example 02

Basic demo

The Next.js pattern: next/dynamic loads PdfEditor with ssr disabled so canvas, window, and the PDF.js worker run in the browser.

  • dynamic(() => import(...), { ssr: false })
  • Same file, name, and height props as the quick start
  • Safe to render from an App Router page

components/basic-pdf-editor.tsx

Open basic demo

Example 03

Custom toolbar

The browser-only editor plus a toolbar render prop. The live bar renames the document, switches tools, and exports the PDF through ToolbarApi.

  • toolbar={(api) => <CustomToolbar api={api} />}
  • Select, draw, highlight, text, image, and signature
  • Undo, redo, zoom, pages, search, and export

components/custom-example.tsx

Open custom toolbar

What the editor includes

PdfEditor views and edits a PDF in the browser. Rendering uses PDF.js. Export uses pdf-lib and writes annotations into a new file. Annotations stay in memory until you export.

  • Text boxes, freehand ink, highlights, images, and signatures
  • Page thumbnails, blank pages, delete, and drag-to-reorder
  • In-document search, zoom, undo, and redo
  • Export that flattens edits into a downloadable PDF

How to create these examples

Install the package, import the stylesheet once, and give the editor a height. The root fills its parent, so a parent with no height collapses the page canvas. file accepts a URL string, URL, File, Blob, ArrayBuffer, or Uint8Array.

1. Install

Peer dependencies are React and React DOM 18 or later. This demo uses pnpm; the same package name works with npm.

Terminalbash
npm install react-web-pdf-editor

2. Quick start

Put the editor in a client component and render it from a route. The live page is /quick-start. Import react-web-pdf-editor/styles.css or the toolbar and pages have no layout.

components/quick-start.tsxtsx
"use client";

import { PdfEditor } from "react-web-pdf-editor";
import "react-web-pdf-editor/styles.css";

export function QuickStart() {
  return (
    <PdfEditor
      file="/file/compressed.tracemonkey-pldi-09.pdf"
      name="Quick Start"
      style={{ height: "100vh" }}
    />
  );
}
app/quick-start/page.tsxtsx
import type { Metadata } from "next";
import { QuickStart } from "@/components/quick-start";

export const metadata: Metadata = {
  title: "Quick start",
  description:
    "A client component that renders PdfEditor with a file URL and a document name.",
};

export default function QuickStartPage() {
  return <QuickStart />;
}

3. Basic demo for Next.js

The editor talks to workers, canvas, and window while it renders. Load it with next/dynamic and ssr: false. The live page is /basic-demo.

components/basic-pdf-editor.tsxtsx
"use client";

import dynamic from "next/dynamic";
import "react-web-pdf-editor/styles.css";

const PdfEditor = dynamic(
  () => import("react-web-pdf-editor").then((mod) => mod.PdfEditor),
  { ssr: false },
);

export function BasicPdfEditor() {
  return (
    <PdfEditor
      file="/file/compressed.tracemonkey-pldi-09.pdf"
      name="compressed.tracemonkey-pldi-09.pdf"
      style={{ height: "100vh" }}
    />
  );
}

4. Custom toolbar

Pass toolbar to draw your own bar. The callback receives ToolbarApi: document name, history, the active tool, zoom, page navigation, search, and export. The live page is /custom, and the full bar lives in components/custom-toolbar.tsx. Start from this smaller toolbar, then add the tools you need.

Starter toolbartsx
"use client";

import type { ToolbarApi } from "react-web-pdf-editor";

export function CustomToolbar({ api }: { api: ToolbarApi }) {
  return (
    <header>
      <span>{api.name}</span>
      <button type="button" onClick={api.undo} disabled={!api.canUndo}>
        Undo
      </button>
      <button type="button" onClick={api.redo} disabled={!api.canRedo}>
        Redo
      </button>
      <button type="button" onClick={() => api.setTool("text")}>
        Text
      </button>
      <button
        type="button"
        onClick={api.exportPdf}
        disabled={api.disabled || api.exporting}
      >
        {api.exporting ? "Saving…" : "Export PDF"}
      </button>
    </header>
  );
}
Pass toolbar to PdfEditortsx
"use client";

import dynamic from "next/dynamic";
import "react-web-pdf-editor/styles.css";
import { CustomToolbar } from "@/components/custom-toolbar";

const PdfEditor = dynamic(
  () => import("react-web-pdf-editor").then((mod) => mod.PdfEditor),
  { ssr: false },
);

export function CustomExample() {
  return (
    <PdfEditor
      file="/file/compressed.tracemonkey-pldi-09.pdf"
      name="Document name"
      style={{ height: "100vh" }}
      toolbar={(api) => <CustomToolbar api={api} />}
    />
  );
}