Search code examples
javascriptreactjs

How to create a custom button in react-pdf-viewer?


I'm using react-pdf-viewer in a React application and need to customise the button images to suit the style of the app. I can get the viewer to display the correct button style but the button then does not do anything when it is clicked, nor does it display the tooltip when hovered over. I've tried attaching onClick functions to the various elements of the button but they only fire on rendering and not when clicked.

This is the main code for the viewer; I'm first trying to get the download button to work and will then use the solution for the other buttons.

import { Viewer, Worker } from '@react-pdf-viewer/core';
import { defaultLayoutPlugin } from '@react-pdf-viewer/default-layout';
import { zoomPlugin } from '@react-pdf-viewer/zoom';
import { getFilePlugin } from '@react-pdf-viewer/get-file';
import { DownloadButton } from './Components/Buttons';

import '@react-pdf-viewer/core/lib/styles/index.css';
import '@react-pdf-viewer/default-layout/lib/styles/index.css';
import '@react-pdf-viewer/toolbar/lib/styles/index.css';

const App = () => {
    const zoomPluginInstance = zoomPlugin();
    const { ZoomPopover } = zoomPluginInstance;

    const getFilePluginInstance = getFilePlugin();
    const { Download } = getFilePluginInstance;

    const renderToolbar = (Toolbar) => (
        <Toolbar>
            {(slots) => {
                const { NumberOfPages, CurrentPageInput, ZoomIn, ZoomOut, Print } = slots;
                return (
                    <div
                        style={{
                            alignItems: 'center',
                            display: 'flex',
                            justifyContent: 'space-between',
                            marginRight: 40
                        }}
                    >
                        <div style={{display: 'flex', alignItems: 'center'}}>
                            <div style={{ padding: '0px 5px' }}>
                                <CurrentPageInput style={{fontSize: 16}} />
                            </div>
                            <div style={{ padding: '0px 5px 3px' }}>
                                / <NumberOfPages /> pages
                            </div>
                        </div>
                        <div className="zoomControls" style={{display: 'flex', alignItems: 'center'}}>
                            <div style={{ padding: '0px 5px' }}>
                                <ZoomOut />
                            </div>
                            <div style={{ padding: '0px 5px', backgroundColor: '#fff', borderRadius: 4 }}>
                                <ZoomPopover />
                            </div>
                            <div style={{ padding: '0px 5px' }}>
                                <ZoomIn />
                            </div>
                        </div>
                        <div style={{display: 'flex', alignItems: 'center'}}>
                            <div style={{ padding: '0px 5px', marginLeft: 'auto' }}>
                                <Print />
                            </div>
                            <div style={{ padding: '0px 5px' }}>
                                <Download>
                                    {() => (
                                        <DownloadButton />
                                    )}
                                </Download>
                            </div>
                        </div>
                    </div>
                );
            }}
        </Toolbar>
    );

    const defaultLayoutPluginInstance = defaultLayoutPlugin({
        renderToolbar,
        sidebarTabs: (defaultTabs) => [defaultTabs[0]],
    });

    return (
        <Worker workerUrl="https://unpkg.com/[email protected]/build/pdf.worker.js">
            <div className="pdfContainer">
                <Viewer
                    fileUrl={'https://file-examples-com.github.io/uploads/2017/10/file-example_PDF_1MB.pdf'}
                    plugins={[defaultLayoutPluginInstance, zoomPluginInstance, getFilePluginInstance]}
                />
            </div>
        </Worker>
    );
};

export default App;

and this is the imported download button


export const DownloadButton = () => (
    <button className="downloadButton" aria-label="Download">
      <img src={process.env.PUBLIC_URL + '/icons/download.svg'} className="btButton" alt="Download" />
    </button>
);

Solution

  • As far as the downloading the file, it seems that you've forgotten to use the props of the download button.

    What you need to do is add the props and then pass the onClick handler to the DownloadButton like so:

    <Download>
        {(props) => (
            <DownloadButton onCLick={props.onClick} />
        )}
    </Download>
    

    Since your DownloadButton is a wrapper around a button you also need to define onClick as a prop there and then pass it down to the HTML button element.

    /**
     * A button used to download the a PDF.
     *
     * @param {Object} [props]
     * @param {*} [props.onClick] The @react-pdf-viewer/get-file click handler.
     */
    export const DownloadButton = (props) => {
        return (
            /** Pass the download button's `onClick` handler to this button. */
            <button
                onClick={props.onClick}
                className="downloadButton"
                aria-label="Download"
            >
                <img
                    src={process.env.PUBLIC_URL + "/icons/download.svg"}
                    className="btButton"
                    alt="Download"
                />
            </button>
        );
    };
    

    As far as the tooltip goes, it seems that you'll have to implement that yourself unless you use the default DownloadButton provided by `@react-pdf-viewer/get-file.