Basic Usage
Anatomy
The following structure demonstrates how to build a React PDF by importing and assembling components. This modular approach gives you the flexibility to customize the viewer as needed.
<RPConfig> {/* Configuration license and pdfjs-dist worker */} <RPProvider> {/* Viewer context provider */} <RPTheme> {/* Theme customization (optional) */} <RPDefaultLayout> {/* Default layout container */} <RPPages /> {/* PDF pages renderer */} </RPDefaultLayout> </RPTheme> </RPProvider></RPConfig>
Remark: For more information on what each part is, please refer to Component.
Basic Implementation
The most basic usage of React PDF needs four components, namely: RPConfig
, RPProvider
, RPDefaultLayout
, and RPPages
.
Here’s how to implement a basic PDF viewer in a React application:
-
Place
<RPConfig>
at the root of your React application. This component should only be used once in your application.src/App.jsx import { RPConfig } from '@pdf-viewer/react'function App() {...return (<><RPConfig licenseKey={YOUR_LICENSE_KEY}>...</RPConfig></>)}export default Appsrc/App.tsx import { RPConfig } from '@pdf-viewer/react'function App() {...return (<><RPConfig licenseKey={YOUR_LICENSE_KEY}>...</RPConfig></>)}export default App -
Create a reusable PDF viewer component that encapsulates the core functionality:
src/components/AppPdfViewer.jsx import { RPProvider, RPDefaultLayout, RPPages } from '@pdf-viewer/react'const AppPdfViewer = () => {return (<RPProvider src="https://cdn.codewithmosh.com/image/upload/v1721763853/guides/web-roadmap.pdf"><RPDefaultLayout><RPPages /></RPDefaultLayout></RPProvider>)}export default AppPdfViewersrc/components/AppPdfViewer.tsx import { RPProvider, RPDefaultLayout, RPPages } from '@pdf-viewer/react'import { type FC } from 'react'const AppPdfViewer: FC = () => {return (<RPProvider src="https://cdn.codewithmosh.com/image/upload/v1721763853/guides/web-roadmap.pdf"><RPDefaultLayout><RPPages /></RPDefaultLayout></RPProvider>)}export default AppPdfViewerThe PDF viewer will automatically adjust to fit its container’s dimensions. You can adjust the dimensions by setting the
style
prop inRPDefaultLayout
. -
Now, you can use
AppPdfViewer
anywhere in your React application. Here is an example of using it in the homepage:src/App.jsx import { RPConfig } from '@pdf-viewer/react'import AppPdfViewer from './AppPdfViewer'function App() {...return (<><RPConfig licenseKey={YOUR_LICENSE_KEY}>...<AppPdfViewer /></RPConfig></>)}export default Appsrc/App.tsx import { RPConfig } from '@pdf-viewer/react'import AppPdfViewer from './AppPdfViewer'function App() {...return (<><RPConfig licenseKey={YOUR_LICENSE_KEY}>...<AppPdfViewer /></RPConfig></>)}export default App
For Next.js applications, we need to set up client-side rendering using two separate components:
-
Import and place
RPConfig
at the root layout by creating a clientAppProviders
and ensure using it only in Client-side:-
Create an
AppProviders
component:app/components/AppProviders.jsx 'use client'import { RPConfig } from '@pdf-viewer/react'function AppProviders({ children, ...props }) {return (<RPConfig {...props}>{children}</RPConfig>)}export default AppProvidersapp/components/AppProviders.tsx 'use client'import { RPConfig, RPConfigProps } from '@pdf-viewer/react'import { type PropsWithChildren } from 'react'function AppProviders({ children, ...props }: PropsWithChildren<RPConfigProps>) {return (<RPConfig {...props}>{children}</RPConfig>)}export default AppProviders -
Ensure
AppProviders
isn’t loaded on Server-side by creating aLazyAppProviders
:app/components/LazyAppProviders.jsx 'use client'import dynamic from 'next/dynamic'const LazyAppProviders = dynamic(() => import('./AppProviders'), {ssr: false})export default LazyAppProvidersapp/components/LazyAppProviders.tsx 'use client'import dynamic from 'next/dynamic'const LazyAppProviders = dynamic(() => import('./AppProviders'), {ssr: false})export default LazyAppProviders -
Then use it in your root layout:
app/layout.jsx import LazyAppProviders from './components/LazyAppProviders'export default function RootLayout({ children }) {return (<html lang="en"><body><LazyAppProviders licenseKey="your-license-key"><main>{children}</main></LazyAppProviders></body></html>)}app/layout.tsx import { type PropsWithChildren } from 'react'import LazyAppProviders from './components/LazyAppProviders'export default function RootLayout({ children }: PropsWithChildren) {return (<html lang="en"><body><LazyAppProviders licenseKey="your-license-key"><main>{children}</main></LazyAppProviders></body></html>)}
-
-
Create a reusable React PDF component:
app/components/AppPdfViewer.jsx 'use client'import { RPProvider, RPDefaultLayout, RPPages } from '@pdf-viewer/react'const AppPdfViewer = () => {return (<RPProvider src="https://cdn.codewithmosh.com/image/upload/v1721763853/guides/web-roadmap.pdf"><RPDefaultLayout><RPPages /></RPDefaultLayout></RPProvider>)}export default AppPdfViewerapp/components/AppPdfViewer.tsx 'use client'import { RPProvider, RPDefaultLayout, RPPages } from '@pdf-viewer/react'const AppPdfViewer = () => {return (<RPProvider src="https://cdn.codewithmosh.com/image/upload/v1721763853/guides/web-roadmap.pdf"><RPDefaultLayout><RPPages /></RPDefaultLayout></RPProvider>)}export default AppPdfViewer -
Create a lazy-loaded wrapper component:
app/components/LazyAppPdfViewer.jsx 'use client'import dynamic from 'next/dynamic'const LazyAppPdfViewer = dynamic(() => import('./AppPdfViewer'), {ssr: false})export default LazyAppPdfViewerapp/components/LazyAppPdfViewer.tsx 'use client'import dynamic from 'next/dynamic'const LazyAppPdfViewer = dynamic(() => import('./AppPdfViewer'), {ssr: false})export default LazyAppPdfViewer
You can now use LazyAppPdfViewer
anywhere in your Next.js application. Here is an example of using it in the index page:
import LazyAppPdfViewer from './components/LazyAppPdfViewer'
export default function Page() { return <LazyAppPdfViewer />}
Key Points
- The viewer requires at minimum:
RPConfig
,RPProvider
,RPDefaultLayout
, andRPPages
- Set dimensions using the
style
prop onRPDefaultLayout
- For Next.js, always use client-side rendering with
dynamic
import - The viewer is responsive and will adapt to its container size
Handling Source of PDF File
The src
prop of the RPProvider
component is designed for flexibility, accepting different types of PDF sources. This allows developers to handle PDFs from various origins, such as URLs, file paths within the project, or Blob objects (e.g., when fetching files from an API). Below is a detailed guide on how to handle each type of source effectively.
URL (HTTP/HTTPS)
If the src
prop is a URL, the component can directly fetch and display the PDF. This is useful for displaying PDFs hosted on an external server.
Example
<RPConfig> <RPProvider src="https://cdn.codewithmosh.com/image/upload/v1721763853/guides/web-roadmap.pdf"> <RPDefaultLayout> <RPPages /> </RPDefaultLayout> </RPProvider></RPConfig>
Best Practices:
- Ensure the URL is accessible and the server supports CORS (Cross-Origin Resource Sharing) if the PDF is hosted on a different domain.
Blob (From API or File Upload)
If the src
prop is a Blob URL (e.g., blob:https://example.com/pdf-document
), it can be used to display generated PDFs or fetch PDFs dynamically such as from a file upload or an API.
Example
// Fetch PDF from an APIconst [pdfBlobUrl, setPdfBlobUrl] = useState(null)const [error, setError] = useState(null)const [isLoading, setIsLoading] = useState(true)
useEffect(() => { const fetchPdf = async () => { try { // Fetch PDF from the API const response = await fetch('https://api.example.com/document') if (!response.ok) { throw new Error('Failed to fetch PDF') } // Convert the response to a Blob const blob = await response.blob() // Generate a Blob URL const blobUrl = URL.createObjectURL(blob) // Update state with the Blob URL setPdfBlobUrl(blobUrl) } catch (err) { // Handle errors setError(err.message) } finally { // Set loading to false setIsLoading(false) } }
// Call the fetch function fetchPdf()
// Cleanup function to revoke the Blob URL when the component unmounts return () => { if (pdfBlobUrl) { URL.revokeObjectURL(pdfBlobUrl) } }}, []) // Empty dependency array ensures this runs only once on mount
return ( <RPConfig> <RPProvider src={pdfBlobUrl}> <RPDefaultLayout> <RPPages /> </RPDefaultLayout> </RPProvider> </RPConfig>)
Best Practices:
- Always revoke Blob URLs using
URL.revokeObjectURL
when the component is destroyed or the Blob is no longer needed to prevent memory leaks - Handle errors during the
fetch
operation and provide fallback content or error messages
Internal File Path
Vite
When using Vite, you have two main approaches to handle PDF files:
- Import in JavaScript: You can directly import PDF files in your JavaScript modules. Vite will resolve the path during the build process. This is ideal for PDFs bundled with your application:
Example
import pdfFile from './assets/document.pdf'
return ( <RPConfig> <RPProvider src={pdfFile}> <RPDefaultLayout> <RPPages /> </RPDefaultLayout> </RPProvider> </RPConfig>)
- Serve from Public Folder: If you prefer to keep your PDFs in the
public
folder, you can serve them directly from there:
Example
<RPConfig> <RPProvider src="/document.pdf"> <RPDefaultLayout> <RPPages /> </RPDefaultLayout> </RPProvider></RPConfig>
Best Practices:
- Use
new URL('./path/to/file.pdf', import.meta.url).href
for importing PDFs as URLs - Place PDFs in
src/assets
for processing through Vite’s asset pipeline - Configure
vite.config.js
to handle PDF files:
vite.config.js
export default { assetsInclude: ['**/*.pdf']}
- Refer to Vite documentation for more information.
Webpack
When using webpack, you have two main approaches to handle PDF files:
-
Import in JavaScript: You can directly import PDF files in your JavaScript modules. Webpack will include these files in your bundle and generate appropriate URLs:
You can import a file right in a JavaScript module. This tells webpack to include that file in the bundle. Or you can use the
public
folder to serve the PDF file.
Example
import pdfFile from './assets/document.pdf'
return ( <RPConfig> <RPProvider src={pdfFile}> <RPDefaultLayout> <RPPages /> </RPDefaultLayout> </RPProvider> </RPConfig>)
- Serve from Public Folder: If you prefer to keep your PDFs in the
public
folder, you can serve them directly from there:
Example
<RPConfig> <RPProvider src="/document.pdf"> <RPDefaultLayout> <RPPages /> </RPDefaultLayout> </RPProvider></RPConfig>
Best Practices:
-
Use
require('./path/to/file.pdf')
or ES modulesimport pdfUrl from './path/to/file.pdf'
-
Configure webpack to handle PDFs using file-loader:
webpack.config.js
module: {rules: [{test: /\.pdf$/,use: [{loader: 'file-loader',options: {name: '[name].[ext]'}}]}]} -
Refer to the following links for more information: