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.
Return Type
Section titled “Return Type”Name | Type | Description |
---|---|---|
updateElement | (pageNumber: number, element: (dimension: {width: number, height: number}, rotate: number, zoom: number) => HTMLElement | JSX.Element) => void | Add a custom element to the specific page |
removeElement | (pageNumber: number, index: number) => void | Remove a custom element from the specific page |
clearElements | (pageNumber: number) => void | Remove all custom elements from the specific page |
elementList | Record<number, Array<HTMLElement | JSX.Element>> | Access the current scale level of the current PDF 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, scale, { x, y } = { x: 0, y: 0 } ) => { const div = document.createElement('div') // set id to element div.id = id // setting style div.style.backgroundColor = 'green' div.style.width = `${100 * scale}px` div.style.height = `${100 * scale}px` div.style.color = 'white' div.style.padding = '2px 4px' div.style.borderRadius = '4px' div.style.position = 'absolute' // set position div.style.top = y * scale + 'px' div.style.left = x * scale + 'px' return div }
// function to create react jsx element const createJSXElement = ( id, removeElement, scale: number ) => { return ( <div id={id} style={{ backgroundColor: 'red', width: `${100 * scale}px`, height: `${100 * scale}px`, color: 'white', padding: '2px 4px', borderRadius: '4px', position: 'absolute', // set position top: '0px', left: '50px', zIndex: 10 }} > <button onClick={() => removeElement(1, 1)}>remove</button> </div> ) }
const CustomElement = () => { const { updateElement, removeElement, clearElements } = useElementPageContext() const [page, setPage] = useState(1) const [x, setX] = useState(0) const [y, setY] = useState(0) const [list, setList] = useState({})
useEffect(() => { const pages = Object.keys(list) // list element Object.entries(list).forEach(([page, items]) => { items.forEach((item, idx) => { updateElement(Number(page), (_prev = [], _dimension, _rotate, scale) => { return [ ..._prev, createHTMLElement(`${page}-${idx}`, scale / 100, { x: item.x, y: item.y }) ] }) }) }) // base element updateElement(1, (_prev = [], _dimension, _rotate, scale) => { return [ ..._prev, // HTML element createHTMLElement('1', scale / 100), // JSX element createJSXElement('2', removeElement, scale / 100) ] })
return () => { pages.forEach((page) => { clearElements(Number(page)) }) clearElements(1) } }, [updateElement, list, removeElement, clearElements])
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])
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> </> ) }
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> ) }
import { useCallback, useState, useEffect, FC } from 'react' import { RPConfig, RPProvider, RPDefaultLayout, RPPages, useElementPageContext } from '@pdf-viewer/react'
const createHTMLElement = ( id: string, scale: number, { x, y }: { x: number; y: number } = { x: 0, y: 0 } ) => { const div = document.createElement('div') // set id to element div.id = id // setting style div.style.backgroundColor = 'green' div.style.width = `${100 * scale}px` div.style.height = `${100 * scale}px` div.style.color = 'white' div.style.padding = '2px 4px' div.style.borderRadius = '4px' div.style.position = 'absolute' // set position div.style.top = y * scale + 'px' div.style.left = x * scale + 'px' return div }
// function to create react jsx element const createJSXElement = ( id: string, removeElement: (page: number, index: number) => void, scale: number ) => { return ( <div id={id} style={{ backgroundColor: 'red', width: `${100 * scale}px`, height: `${100 * scale}px`, color: 'white', padding: '2px 4px', borderRadius: '4px', position: 'absolute', // set position top: '0px', left: '50px', zIndex: 10 }} > <button onClick={() => removeElement(1, 1)}>remove</button> </div> ) }
const CustomElement = () => { const { updateElement, removeElement, clearElements } = useElementPageContext() const [page, setPage] = useState(1) const [x, setX] = useState(0) const [y, setY] = useState(0) const [list, setList] = useState<Record<number, Array<{ x: number; y: number }>>>({})
useEffect(() => { const pages = Object.keys(list) // list element Object.entries(list).forEach(([page, items]) => { items.forEach((item, idx) => { updateElement(Number(page), (_prev = [], _dimension, _rotate, scale) => { return [ ..._prev, createHTMLElement(`${page}-${idx}`, scale / 100, { x: item.x, y: item.y }) ] }) }) }) // base element updateElement(1, (_prev = [], _dimension, _rotate, scale) => { return [ ..._prev, // HTML element createHTMLElement('1', scale / 100), // JSX element createJSXElement('2', removeElement, scale / 100) ] })
return () => { pages.forEach((page) => { clearElements(Number(page)) }) clearElements(1) } }, [updateElement, list, removeElement, clearElements])
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])
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> </> ) }
export const AppPdfViewer: FC = () => { 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> ) }