Skip to content

Recipes

Wojciech Maj edited this page Jun 21, 2019 · 15 revisions

Note: For the sake of clarity, the examples provided are using experimental class properties syntax, support of which may be enabled using @babel/plugin-proposal-class-properties plugin.

Display single page

import React, { Component } from 'react';
import { Document, Page } from 'react-pdf/src/entry.webpack';

import samplePDF from './test.pdf';

export default class Test extends Component {
  render() {
    return (
      <Document
        file={samplePDF}
        onLoadSuccess={this.onDocumentLoadSuccess}
      >
        <Page pageNumber={1} />
      </Document>
    );
  }
}

Display all pages

Please note that this approach may cause performance issues.

import React, { Component } from 'react';
import { Document, Page } from 'react-pdf';

import samplePDF from './test.pdf';

export default class Test extends Component {
  state = {
    numPages: null,
  }

  onDocumentLoadSuccess = (document) => {
    const { numPages } = document;
    this.setState({
      numPages,
    });
  };

  render() {
    const { numPages } = this.state;

    return (
      <Document
        file={samplePDF}
        onLoadSuccess={this.onDocumentLoadSuccess}
      >
        {Array.from(
          new Array(numPages),
          (el, index) => (
            <Page
              key={`page_${index + 1}`}
              pageNumber={index + 1}
            />
          ),
        )}
      </Document>
    );
  }
}

Display single page with navigation

import React, { Component } from 'react';
import { Document, Page } from 'react-pdf';

import samplePDF from './test.pdf';

export default class Test extends Component {
  state = {
    numPages: null,
    pageNumber: 1,
  }

  onDocumentLoadSuccess = (document) => {
    const { numPages } = document;
    this.setState({
      numPages,
      pageNumber: 1,
    });
  };

  changePage = offset => this.setState(prevState => ({
    pageNumber: prevState.pageNumber + offset,
  }));

  previousPage = () => this.changePage(-1);

  nextPage = () => this.changePage(1);

  render() {
    const { numPages, pageNumber } = this.state;

    return (
      <React.Fragment>
        <Document
          file={samplePDF}
          onLoadSuccess={this.onDocumentLoadSuccess}
        >
          <Page pageNumber={pageNumber} />
        </Document>
        <div>
          <p>
            Page {pageNumber || (numPages ? 1 : '--')} of {numPages || '--'}
          </p>
          <button
            type="button"
            disabled={pageNumber <= 1}
            onClick={this.previousPage}
          >
            Previous
          </button>
          <button
            type="button"
            disabled={pageNumber >= numPages}
            onClick={this.nextPage}
          >
            Next
          </button>
        </div>
      </React.Fragment>
    );
  }
}

Highlight text on the page

import React, { Component } from 'react';
import { Document, Page } from 'react-pdf';

import samplePDF from './test.pdf';

// https://gist.github.com/wojtekmaj/f265f55e89ccb4ce70fbd2f8c7b1d95d
const highlightPattern = (text, pattern) => {
  const splitText = text.split(pattern);

  if (splitText.length <= 1) {
    return text;
  }

  const matches = text.match(pattern);

  return splitText.reduce((arr, element, index) => (matches[index] ? [
    ...arr,
    element,
    <mark>
      {matches[index]}
    </mark>,
  ] : [...arr, element]), []);
};

export default class Test extends Component {
  state = {
    searchText: '',
  }

  makeTextRenderer = searchText => textItem => highlightPattern(textItem.str, searchText);

  onChange = event => this.setState({ searchText: event.target.value });

  render() {
    const { searchText } = this.state;

    return (
      <React.Fragment>
        <Document
          file={samplePDF}
          onLoadSuccess={this.onDocumentLoadSuccess}
        >
          <Page
            pageNumber={1}
            customTextRenderer={this.makeTextRenderer(searchText)}
          />
        </Document>
        <div>
          <label htmlFor="search">Search:</label>
          <input type="search" id="search" value={searchText} onChange={this.onChange} />
        </div>
      </React.Fragment>
    );
  }
}

Display interactive Table of Contents

Note that this example is nearly identical to the next one. onItemClick can be both used in Document and Outline components.

import React, { Component } from 'react';
import { Document, Outline, Page } from 'react-pdf';

import samplePDF from './test.pdf';

export default class Test extends Component {
  state = {
    pageNumber: 1,
  };

  onItemClick = ({ pageNumber }) => this.setState({ pageNumber });

  render() {
    const { pageNumber } = this.state;

    return (
      <Document file={samplePDF}>
        <Outline onItemClick={this.onItemClick} />
        <Page
          pageNumber={pageNumber || 1}
        />
      </Document>
    );
  }
}

Handle external links

Note that this example is nearly identical to the previous one. onItemClick can be both used in Document and Outline components.

import React, { Component } from 'react';
import { Document, Outline, Page } from 'react-pdf';

import samplePDF from './test.pdf';

export default class Test extends Component {
  state = {
    pageNumber: 1,
  };

  onItemClick = ({ pageNumber }) => this.setState({ pageNumber });

  render() {
    const { pageNumber } = this.state;

    return (
      <Document
        file={samplePDF}
        onItemClick={this.onItemClick}
      >
        <Page
          pageNumber={pageNumber || 1}
        />
      </Document>
    );
  }
}