Accessing the Viewer's Elements
React PDF provides data-rp
attributes to access specific elements so that you can customize the viewer easily.
Attribute | description |
---|---|
data-rp="moreOptionsDropdown" | The dropdown container of the More Options menu |
data-rp="page-{pageNumber}" | Page element Remark: Replace pageNumber with a specific value (e.g., data-rp="page-21" ) |
data-rp="page-{pageNumber}-canvas" | Page canvas element Remark: Replace pageNumber with a specific value (e.g., data-rp="page-21-canvas" ) |
data-rp="page-{pageNumber}-textLayer" | Page text layer element Remark: Replace pageNumber with a specific value (e.g., data-rp="page-21-textLayer" ) |
data-rp="pages" | Page container element |
data-rp="sidebar" | Sidebar container |
data-rp="thumbnailSidebar" | Thumbnail sidebar container |
data-rp="topBar" | The top bar container which consists of 3 sections (i.e. left, center and right) |
data-rp="topBarCenter" | The middle section of the top bar container which consists of the zoom feature |
data-rp="topBarLeft" | The left section of the top bar container which consists of search and page navigation |
data-rp="topBarRight" | The right section of the top bar container which consists of the rest of the features, including those in the More Options |
Remark: If you would like to access other elements, please submit a request on GitHub.
Example: Accessing topBarRight
Element to Prepend a Button
-
Create a button element
const buttonElement = useMemo(() => {const button = document.createElement('button')button.innerHTML = 'N'return button}, [])const buttonElement = useMemo(() => {const button = document.createElement('button')button.innerHTML = 'N'return button}, []) -
Get the element of the right section of the top bar container
const topBarRight = ref.current?.querySelector('[data-rp="topBarRight"]')const topBarRight = ref.current?.querySelector('[data-rp="topBarRight"]') -
Add a button element to the element
topBarRight?.prepend(buttonElement)topBarRight?.prepend(buttonElement) -
Remove the button element when the component is cleaned up
const cleanupOnLoaded = useCallback(() => {if (buttonElement) {buttonElement.remove()}}, [buttonElement])const cleanupOnLoaded = useCallback(() => {if (buttonElement) {buttonElement.remove()}}, [buttonElement])Remark: Use this function for dev mode due to the useEffect’s caveats
Putting everything together
import { useRef, useCallback, useMemo } from 'react'import { RPConfig, RPProvider, RPDefaultLayout, RPPages } from '@pdf-viewer/react'
export const AppPdfViewer = () => { const ref = useRef(null)
// Create the button element. const buttonElement = useMemo(() => { const button = document.createElement('button') button.innerHTML = 'N' return button }, [])
const handleLoaded = useCallback(() => { // Get the element of React PDF. const topBarRight = ref.current?.querySelector('[data-rp="topBarRight"]') // Add the button element to the top bar. topBarRight?.prepend(buttonElement) }, [buttonElement])
// Remove the button element when the component is cleaned up. const cleanupOnLoaded = useCallback(() => { if (buttonElement) { buttonElement.remove() } }, [buttonElement])
return ( <RPConfig licenseKey="YOUR_LICENSE_KEY"> <RPProvider src="https://cdn.codewithmosh.com/image/upload/v1721763853/guides/web-roadmap.pdf"> <RPDefaultLayout ref={ref} onLoaded={handleLoaded} cleanupOnLoaded={cleanupOnLoaded}> <RPPages /> </RPDefaultLayout> </RPProvider> </RPConfig> )}
import { useRef, useCallback, useMemo } from 'react'import { RPConfig, RPProvider, RPDefaultLayout, RPPages } from '@pdf-viewer/react'
export const AppPdfViewer = () => { const ref = useRef<HTMLDivElement>(null)
// Create the button element. const buttonElement = useMemo(() => { const button = document.createElement('button') button.innerHTML = 'N' return button }, [])
const handleLoaded = useCallback(() => { // Get the element of React PDF. const topBarRight = ref.current?.querySelector('[data-rp="topBarRight"]') // Add the button element to the top bar. topBarRight?.prepend(buttonElement) }, [buttonElement])
// Remove the button element when the component is cleaned up. const cleanupOnLoaded = useCallback(() => { if (buttonElement) { buttonElement.remove() } }, [buttonElement])
return ( <RPConfig licenseKey="YOUR_LICENSE_KEY"> <RPProvider src="https://cdn.codewithmosh.com/image/upload/v1721763853/guides/web-roadmap.pdf"> <RPDefaultLayout ref={ref} onLoaded={handleLoaded} cleanupOnLoaded={cleanupOnLoaded}> <RPPages /> </RPDefaultLayout> </RPProvider> </RPConfig> )}
Select moreOptionsDropdown
Element
Because More Options
dropdown is not visible by default, you will need to use MutationObserver
API to monitor changes of a specific DOM element.
An example: Accessing moreOptionsDropdown
Element to Prepend a Button
-
Define Mutation Observer Configuration
const config = {attributes: false,childList: true,subtree: false}let observerconst config = {attributes: false,childList: true,subtree: false}let observer: MutationObserver -
Attach a Button to the Dropdown using Observer
const handleMoreOptionsMount = useCallback((elemContainer) => {const observerCallback = () => {const moreOptions = elemContainer.querySelector('[data-rp="moreOptionsDropdown"]')if (moreOptions) {moreOptions?.prepend(buttonElement)}}observer = new MutationObserver(observerCallback)observer.observe(elemContainer, config)},[buttonElement])const handleMoreOptionsMount = useCallback((elemContainer: Element) => {const observerCallback = () => {const moreOptions = elemContainer.querySelector('[data-rp="moreOptionsDropdown"]')if (moreOptions) {moreOptions?.prepend(buttonElement)}}observer = new MutationObserver(observerCallback)observer.observe(elemContainer, config)},[buttonElement]) -
Cleanup the Observer on Unmount
useEffect(() => {return () => observer?.disconnect()}, [])useEffect(() => {return () => observer?.disconnect()}, [])
Putting everything together
import { useRef, useCallback, useMemo, useEffect } from 'react'import { RPConfig, RPProvider, RPDefaultLayout, RPPages } from '@pdf-viewer/react'
// Options for the Observerconst config = { attributes: false, childList: true, subtree: false}
let observer
export const AppPdfViewer = () => { const ref = useRef(null)
// Create the button element const buttonElement = useMemo(() => { const button = document.createElement('button') button.innerHTML = 'N' return button }, [])
const handleMoreOptionsMount = useCallback( (elemContainer) => { const observerCallback = () => { const moreOptions = elemContainer.querySelector('[data-rp="moreOptionsDropdown"]') if (moreOptions) { moreOptions?.prepend(buttonElement) } }
observer = new MutationObserver(observerCallback) observer.observe(elemContainer, config) }, [buttonElement] )
const handleLoaded = useCallback(() => { const elemContainer = ref.current?.querySelector('[data-rp="container"]') if (elemContainer) { handleMoreOptionsMount(elemContainer) } }, [handleMoreOptionsMount])
// Remove the button element when the component is cleaned up const cleanupOnLoaded = useCallback(() => { if (buttonElement) { buttonElement.remove() } }, [buttonElement])
// Cleanup the Observer on Unmount useEffect(() => { return () => observer?.disconnect() }, [])
return ( <RPConfig licenseKey="YOUR_LICENSE_KEY"> <RPProvider src="https://cdn.codewithmosh.com/image/upload/v1721763853/guides/web-roadmap.pdf"> <RPDefaultLayout ref={ref} onLoaded={handleLoaded} cleanupOnLoaded={cleanupOnLoaded}> <RPPages /> </RPDefaultLayout> </RPProvider> </RPConfig> )}
import { useRef, useCallback, useMemo, useEffect } from 'react'import { RPConfig, RPProvider, RPDefaultLayout, RPPages } from '@pdf-viewer/react'
// Options for the Observerconst config = { attributes: false, childList: true, subtree: false}
let observer: MutationObserver
export const AppPdfViewer = () => { const ref = useRef<HTMLDivElement>(null)
// Create the button element const buttonElement = useMemo(() => { const button = document.createElement('button') button.innerHTML = 'N' return button }, [])
const handleMoreOptionsMount = useCallback( (elemContainer: Element) => { const observerCallback = () => { const moreOptions = elemContainer.querySelector('[data-rp="moreOptionsDropdown"]') if (moreOptions) { moreOptions?.prepend(buttonElement) } }
observer = new MutationObserver(observerCallback) observer.observe(elemContainer, config) }, [buttonElement] )
const handleLoaded = useCallback(() => { const elemContainer = ref.current?.querySelector('[data-rp="container"]') if (elemContainer) { handleMoreOptionsMount(elemContainer) } }, [handleMoreOptionsMount])
// Remove the button element when the component is cleaned up const cleanupOnLoaded = useCallback(() => { if (buttonElement) { buttonElement.remove() } }, [buttonElement])
// Cleanup the Observer on Unmount useEffect(() => { return () => observer?.disconnect() }, [])
return ( <RPConfig licenseKey="YOUR_LICENSE_KEY"> <RPProvider src="https://cdn.codewithmosh.com/image/upload/v1721763853/guides/web-roadmap.pdf"> <RPDefaultLayout ref={ref} onLoaded={handleLoaded} cleanupOnLoaded={cleanupOnLoaded}> <RPPages /> </RPDefaultLayout> </RPProvider> </RPConfig> )}