Skip to content

Accessing the Viewer's Elements

React PDF provides data-rp attributes to access specific elements so that you can customize the viewer easily.

Attributedescription
data-rp="moreOptionsDropdown"The dropdown container of the More Options menu
data-rp="page-{pageNumber}"Page element
Remark: ReplacepageNumber with a specific value (e.g., data-rp="page-21")
data-rp="page-{pageNumber}-canvas"Page canvas element
Remark: ReplacepageNumber with a specific value (e.g., data-rp="page-21-canvas")
data-rp="page-{pageNumber}-textLayer"Page text layer element
Remark: ReplacepageNumber 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

  1. Create a button element

    const buttonElement = useMemo(() => {
    const button = document.createElement('button')
    button.innerHTML = 'N'
    return button
    }, [])
  2. Get the element of the right section of the top bar container

    const topBarRight = ref.current?.querySelector('[data-rp="topBarRight"]')
  3. Add a button element to the element

    topBarRight?.prepend(buttonElement)
  4. Remove the button element when the component is cleaned up

    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>
)
}

Screenshot 2568-02-21 at 13.45.58

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

  1. Define Mutation Observer Configuration

    const config = {
    attributes: false,
    childList: true,
    subtree: false
    }
    let observer
  2. 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]
    )
  3. Cleanup the Observer on Unmount

    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 Observer
const 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>
)
}

Screenshot 2568-02-21 at 14.05.30