Skip to content
useElementPageContext Organization

The useElementPageContext hook provides a function to add custom elements to a PDF page.

It enables you to create custom elements such as a bounding box, a shape or an image for a specified page.

This is useful for labelling certain parts of a PDF page or displaying certain content dynamically.

NameTypeDescription
clearElements(pageNumber: number) => voidRemove all custom elements from the specific page
elementListRecord<number, Array<HTMLElement | JSX.Element>>Access the current scale level of the current PDF page
removeElement(pageNumber: number, index: number) => voidRemove a custom element from the specific page
scrollToElement(page: number, index: number, config?: { behavior: ‘smooth’ | ‘auto’ | ‘instant’ }) => voidScroll to a specific element on the given page, centering it in the viewer. The default scroll behavior is ‘smooth’
updateElement(pageNumber: number, element: (dimension: {width: number, height: number}, rotate: number, zoom: number) => HTMLElement | JSX.Element) => voidAdd a custom element to the specific page

To ensure the element page context can be accessed, you will need to use useElementPageContext inside a component which is a child of RPProvider.

This example shows how to create a CustomElementPage component which uses useElementPageContext to handle the element page functionality.

import { useCallback, useState, useEffect } from 'react'
import {
RPConfig,
RPProvider,
RPDefaultLayout,
RPPages,
useElementPageContext
} from '@pdf-viewer/react'
const createHTMLElement = (
id,
pageDimension,
position = { x: 0, y: 0 }
) => {
const div = document.createElement('div')
// set id to element
div.id = id
// setting style
div.style.backgroundColor = 'green'
// set dimension as percentage of page dimension
div.style.width = `${(100 / pageDimension.width) * 100}%`
div.style.height = `${(100 / pageDimension.height) * 100}%`
div.style.color = 'white'
div.style.padding = '2px 4px'
div.style.borderRadius = '4px'
div.style.position = 'absolute'
// set position as percentage of page dimension
div.style.top = `${(position.y / pageDimension.height) * 100}%`
div.style.left = `${(position.x / pageDimension.width) * 100}%`
return div
}
// function to create react jsx element
const createJSXElement = (
id,
pageDimension,
position = { x: 0, y: 0 },
removeElement
) => {
return (
<div
id={id}
style={{
backgroundColor: 'red',
// set dimension as percentage of page dimension
width: `${(100 / pageDimension.width) * 100}%`,
height: `${(100 / pageDimension.height) * 100}%`,
color: 'white',
padding: '2px 4px',
borderRadius: '4px',
position: 'absolute',
// set position as percentage of page dimension
top: `${(position.y / pageDimension.height) * 100}%`,
left: `${(position.x / pageDimension.width) * 100}%`,
zIndex: 10
}}
>
<button onClick={removeElement}>remove</button>
</div>
)
}
const CustomElement = () => {
const { updateElement, clearElements, scrollToElement } = useElementPageContext()
const [page, setPage] = useState(1)
const [x, setX] = useState(0)
const [y, setY] = useState(0)
const [list, setList] = useState({
[1]: [
{ x: 0, y: 0 },
{
x: 50,
y: 50,
removable: true
}
]
})
useEffect(() => {
// assume page dimension at scale 100% is 612 x 792
const pageDimension = { width: 612, height: 792 }
const pages = Object.keys(list)
// list element
Object.entries(list).forEach(([page, items]) => {
items.forEach((item, idx) => {
updateElement(Number(page), (_prev = [], _dimension, _rotate, _scale) => {
const id = `${page}-${idx}`
const newElement = item.removable
? createJSXElement(
id,
pageDimension,
{
x: item.x,
y: item.y
},
item.removable ? () => removeItem(Number(page), idx) : undefined
)
: createHTMLElement(id, pageDimension, {
x: item.x,
y: item.y
})
return [..._prev, newElement]
})
})
})
return () => {
pages.forEach((page) => {
clearElements(Number(page))
})
clearElements(1)
}
}, [updateElement, list, clearElements])
// remove item from list
const removeItem = useCallback((page, index) => {
setList((prev) => {
const newList = { ...prev }
newList[page] = newList[page].filter((_, i) => i !== index)
return newList
})
}, [])
const handleClear = useCallback(() => {
setList((prev) => {
const newList = { ...prev }
delete newList[page]
return newList
})
}, [page])
const handleAdd = useCallback(() => {
setList((prev) => ({
...prev,
[page]: [
...(prev[page] || []),
{
x,
y
}
]
}))
}, [page, x, y])
const handleGoToElement = useCallback(() => {
scrollToElement(1, 0)
}, [scrollToElement])
return (
<>
<div>
page: <input type="number" value={page} onChange={(e) => setPage(Number(e.target.value))} />
</div>
<div>
x: <input type="number" value={x} onChange={(e) => setX(Number(e.target.value))} />
</div>
<div>
y: <input type="number" value={y} onChange={(e) => setY(Number(e.target.value))} />
</div>
<button onClick={handleClear}>clear</button>
<button onClick={handleAdd}>add</button>
<button onClick={handleGoToElement}>go to first element on page 1</button>
</>
)
}
export const AppPdfViewer = () => {
return (
<RPConfig licenseKey="YOUR_LICENSE_KEY">
<RPProvider src="https://cdn.codewithmosh.com/image/upload/v1721763853/guides/web-roadmap.pdf">
<CustomElement />
<RPDefaultLayout>
<RPPages />
</RPDefaultLayout>
</RPProvider>
</RPConfig>
)
}

An example of how to use useElementPageContext hook