Skip to content
Build Your Own Toolbar with Ant Design

This guide walks through building a custom PDF viewer toolbar with Ant Design (antd). You use React PDF Kit for PDF rendering and Ant Design for toolbar UI such as icons, theming, and custom layout.

The library supports two ways to build with Ant Design:

  1. Build with Ant Design using the default toolbar - Use the built-in RPLayout and RPHorizontalBar with a slots map to show or hide default tools, and the icons prop to swap in @ant-design/icons. Optionally wrap in RPTheme with customVariables to style the toolbar (often driven by theme.useToken()).
  2. Build with Ant Design using the Context API - Build the entire toolbar from scratch with Ant Design only (Card, Flex, Button, Input, etc.) and wire every action through the library’s React Context hooks (zoom, pagination, search, print, download). Full control over layout and styling.

Build with Ant Design using the default toolbar

Section titled “Build with Ant Design using the default toolbar”

The default toolbar layout is provided by the library. You can choose which tools to show or hide, and override icons with @ant-design/icons dependency.

Use RPLayout and RPHorizontalBar with a slots map to show or hide built-in tools, and pass the icons prop to replace the default icons.

  1. Define an enum (or object) for the toolbar slot keys the viewer expects. This keeps slot names in one place and matches the keys used by RPHorizontalBar.

    src/lib/types.js
    export const PDF_VIEWER_TOOL = Object.freeze({
    searchTool: "searchTool",
    pageNavigationTool: "pageNavigationTool",
    zoomTool: "zoomTool",
    themeSwitcher: "themeSwitcher",
    downloadTool: "downloadTool",
    openFileTool: "openFileTool",
    printTool: "printTool",
    fullscreenTool: "fullscreenTool",
    jumpNavigationTool: "jumpNavigationTool",
    selectionModeTool: "selectionModeTool",
    rotateTool: "rotateTool",
    viewModeTool: "viewModeTool",
    scrollModeTool: "scrollModeTool",
    documentProperties: "documentProperties",
    thumbnailTool: "thumbnailTool",
    sidebarEnable: "sidebarEnable",
    dropFileZone: "dropFileZone",
    });
  2. Build a slots object that enables only the tools you want. For each slot key, set true to use the default tool or false to hide it. No custom components are required; the library’s default tools are used and you only control visibility.

    src/components/AppCustomizePdfViewer.jsx
    import { useMemo } from "react";
    import { PDF_VIEWER_TOOL } from "../lib/types";
    const slots = Object.values(PDF_VIEWER_TOOL);
    const AVAILABLE_TOOLS = [
    PDF_VIEWER_TOOL.searchTool,
    PDF_VIEWER_TOOL.zoomTool,
    PDF_VIEWER_TOOL.downloadTool,
    PDF_VIEWER_TOOL.printTool,
    ];
    const renderSlots = Object.fromEntries(
    slots.map((key) => {
    return [key, AVAILABLE_TOOLS.includes(key)];
    }),
    );
    • AVAILABLE_TOOLS: Array of slot keys to show in the toolbar; all other slots are disabled.
    • renderSlots: Map of every slot key to true (show default tool) or false (hide).
  3. (Optional) Wrap the viewer in RPTheme and pass customVariables to style the default toolbar (tooltip background, button padding, border radius, text color).

    With Ant Design, you can keep these as fixed CSS values or derive them from theme.useToken() so the toolbar tracks ConfigProvider tokens (see step 4).

    <RPTheme
    customVariables={{
    "--rp-tooltip-background-color": "#0000008a",
    "--rp-button-padding": "6px 8px",
    "--rp-button-border-radius": "6px",
    "--rp-text-color": "#0000008a",
    }}
    >
    {/* RPProvider and RPLayout go here */}
    </RPTheme>
  4. Use RPProvider with your PDF src, then RPLayout with toolbar.topbar.component set to RPHorizontalBar. Pass slots (from step 2) and icons to replace default icons with components from @ant-design/icons. Use theme.useToken() for RPTheme variables and for consistent icon color and size.

    src/components/AppCustomizePdfViewer.jsx
    import {
    DownloadOutlined,
    PrinterOutlined,
    SearchOutlined,
    ZoomInOutlined,
    ZoomOutOutlined,
    } from "@ant-design/icons";
    import { theme } from "antd";
    import { RPProvider, RPPages, RPLayout, RPHorizontalBar, RPTheme } from "@react-pdf-kit/viewer";
    import { useMemo } from "react";
    import { PDF_VIEWER_TOOL } from "../lib/types";
    const slots = Object.values(PDF_VIEWER_TOOL);
    const AVAILABLE_TOOLS = [
    PDF_VIEWER_TOOL.searchTool,
    PDF_VIEWER_TOOL.zoomTool,
    PDF_VIEWER_TOOL.downloadTool,
    PDF_VIEWER_TOOL.printTool,
    ];
    const renderSlots = Object.fromEntries(
    slots.map((key) => {
    return [key, AVAILABLE_TOOLS.includes(key)];
    }),
    );
    const AppCustomizePdfViewer = () => {
    const { token } = theme.useToken();
    const rpThemeVars = useMemo(
    () => ({
    "--rp-tooltip-background-color": token.colorText,
    "--rp-button-padding": "6px 8px",
    "--rp-button-border-radius": `${token.borderRadius}px`,
    "--rp-text-color": token.colorTextSecondary,
    }),
    [token],
    );
    const iconStyle = useMemo(
    () => ({
    fontSize: 16,
    color: token.colorPrimary,
    }),
    [token.colorPrimary],
    );
    return (
    <RPTheme customVariables={rpThemeVars}>
    <RPProvider src="https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf">
    <div
    style={{
    flex: 1,
    minHeight: 0,
    display: "flex",
    flexDirection: "column",
    }}
    >
    <RPLayout
    toolbar={{
    topbar: {
    component: (
    <RPHorizontalBar
    slots={renderSlots}
    icons={{
    searchIcon: <SearchOutlined style={iconStyle} />,
    zoomInIcon: <ZoomInOutlined style={iconStyle} />,
    zoomOutIcon: <ZoomOutOutlined style={iconStyle} />,
    downloadIcon: <DownloadOutlined style={iconStyle} />,
    printIcon: <PrinterOutlined style={iconStyle} />,
    }}
    />
    ),
    },
    }}
    >
    <RPPages />
    </RPLayout>
    </div>
    </RPProvider>
    </RPTheme>
    );
    };
    export default AppCustomizePdfViewer;

An image of customize pdf toolbar with Ant Design

Notes

  • Use RPHorizontalBar to render the default horizontal toolbar. Control which tools are visible with slots and override the icons with the icons prop.
  • Use RPLayout to wrap the toolbar and RPPages.

Build with Ant Design using the Context API

Section titled “Build with Ant Design using the Context API”

Build the entire toolbar yourself with Ant Design only. Use Card, Flex, Button, Input, Tooltip, Typography, and icons from @ant-design/icons, and keep the toolbar inside RPProvider so it can use the context hooks. You control layout and styling completely.

Key pieces:

  • App: Wrap React PDF in RPConfig (with license key) and render the viewer component (e.g. AppPdfViewer).
  • AppPdfViewer: Use RPProvider with a PDF src, a sized container, the Ant Design toolbar CustomHorizontalBar, and RPPages.
  • CustomHorizontalBar: Your Ant Design toolbar: Card, Flex, and composed Zoom, Pagination, Download, Print, and Search tools.
  • Tool components: Each tool uses one hook from @react-pdf-kit/viewer for behavior and renders only Ant Design controls.

The same hooks power the built-in tools when you use slots on RPHorizontalBar, and the custom Ant Design tool components when you use this Context API approach.

Ant Design tool componentHookPurpose
ZoomTooluseZoomContextZoom in/out via setZoomLevel
PaginationToolusePaginationContextPage index, total, nextPage, prevPage
DownloadTooluseFileDownloadTrigger file download
PrintToolusePrintContextTrigger print
SearchTooluseSearchContextQuery, set query, prev/next match, counts
  1. At the root of your app, wrap the React PDF Viewer component in RPConfig and pass your domain token. Render AppPdfViewer inside it so the PDF viewer and its configuration are available to the rest of the tree.

    src/App.jsx
    import "./App.css";
    import { RPConfig } from "@react-pdf-kit/viewer";
    import AppPdfViewer from "./components/AppPdfViewer";
    function App() {
    return (
    <RPConfig licenseKey={"YOUR_DOMAIN_TOKEN"}>
    <AppPdfViewer />
    </RPConfig>
    );
    }
    export default App;
  2. Create the AppPdfViewer component. Use RPProvider with your PDF URL and a container div (or any layout) that holds the toolbar and RPPages. The toolbar must stay inside RPProvider so the context hooks (zoom, pagination, search, and so on) are available.

    src/components/AppPdfViewer.jsx
    import { RPProvider, RPPages } from "@react-pdf-kit/viewer";
    import { CustomHorizontalBar } from "./CustomHorizontalBar";
    const AppPdfViewer = () => {
    return (
    <RPProvider src="https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf">
    <div
    style={{
    width: "100%",
    height: "600px",
    }}
    >
    <CustomHorizontalBar />
    <RPPages />
    </div>
    </RPProvider>
    );
    };
    export default AppPdfViewer;
  3. Create the CustomHorizontalBar component using Ant Design’s Card and Flex. Put zoom, pagination, download, and print in one group, and place the search control in a second group aligned to the right so the layout stays clear. Use theme.useToken() for borders and backgrounds so the bar matches your Ant Design theme.

    src/components/CustomHorizontalBar.jsx
    import { Card, Flex, theme } from "antd";
    import { ZoomTool } from "./ZoomTool";
    import { PaginationTool } from "./PaginationTool";
    import { DownloadTool } from "./DownloadTool";
    import { PrintTool } from "./PrintTool";
    import { SearchTool } from "./SearchTool";
    export const CustomHorizontalBar = () => {
    const { token } = theme.useToken();
    return (
    <Card
    size="small"
    style={{
    borderBottom: "none",
    borderRadius: "8px 8px 0 0",
    background: token.colorPrimaryBg,
    borderColor: token.colorPrimaryBorder,
    }}
    styles={{
    body: {
    padding: "6px 12px",
    borderBottom: "none",
    borderRadius: "8px 8px 0 0",
    },
    }}
    >
    <Flex align="center" justify="space-between" gap="small">
    <Flex
    align="center"
    gap={4}
    style={{
    border: `1px solid ${token.colorPrimaryBorder}`,
    borderRadius: token.borderRadius,
    padding: "4px 8px",
    background: token.colorBgContainer,
    }}
    >
    <ZoomTool />
    <PaginationTool />
    <DownloadTool />
    <PrintTool />
    </Flex>
    <Flex align="center" justify="flex-end" flex={1}>
    <SearchTool />
    </Flex>
    </Flex>
    </Card>
    );
    };
  4. Each toolbar action is a small component that uses one hook from @react-pdf-kit/viewer for behavior and Ant Design components for the UI. Create the following files.

    4.1 ZoomTool: Use the useZoomContext hook to control zoom. Add zoom in and zoom out controls that change the level by 10 each step, clamped between 10 and 1000.

    src/components/ZoomTool.jsx
    import { ZoomInOutlined, ZoomOutOutlined } from "@ant-design/icons";
    import { Button, Tooltip } from "antd";
    import { useZoomContext } from "@react-pdf-kit/viewer";
    import { useCallback } from "react";
    export const ZoomTool = () => {
    const { setZoomLevel } = useZoomContext();
    const handleZoomIn = useCallback(() => {
    setZoomLevel((prev) => Math.min(prev + 10, 1000));
    }, [setZoomLevel]);
    const handleZoomOut = useCallback(() => {
    setZoomLevel((prev) => Math.max(prev - 10, 10));
    }, [setZoomLevel]);
    return (
    <>
    <Tooltip title="Zoom out">
    <Button
    type="text"
    size="small"
    icon={<ZoomOutOutlined />}
    onClick={handleZoomOut}
    aria-label="Zoom out"
    />
    </Tooltip>
    <Tooltip title="Zoom in">
    <Button
    type="text"
    size="small"
    icon={<ZoomInOutlined />}
    onClick={handleZoomIn}
    aria-label="Zoom in"
    />
    </Tooltip>
    </>
    );
    };

    4.2 PaginationTool: Use the usePaginationContext hook to read the current page and total page count. Add previous and next actions and a read-only field showing the current page with the total beside it (for example 3 / 12).

    src/components/PaginationTool.jsx
    import { ArrowDownOutlined, ArrowUpOutlined } from "@ant-design/icons";
    import { Button, Input, Space, Tooltip, Typography } from "antd";
    import { usePaginationContext } from "@react-pdf-kit/viewer";
    export const PaginationTool = () => {
    const { focusedPage, totalPages, nextPage, prevPage } = usePaginationContext();
    return (
    <Space size={0} align="center">
    <Tooltip title="Previous page">
    <Button
    type="text"
    size="small"
    icon={<ArrowUpOutlined />}
    onClick={prevPage}
    aria-label="Previous page"
    />
    </Tooltip>
    <Tooltip title="Current page">
    <Input
    readOnly
    value={focusedPage}
    size="small"
    variant="outlined"
    style={{ width: 48 }}
    styles={{ input: { textAlign: "center" } }}
    />
    </Tooltip>
    <Typography.Text type="secondary" style={{ paddingInline: 4, minWidth: 28 }}>
    / {totalPages}
    </Typography.Text>
    <Tooltip title="Next page">
    <Button
    type="text"
    size="small"
    icon={<ArrowDownOutlined />}
    onClick={nextPage}
    aria-label="Next page"
    />
    </Tooltip>
    </Space>
    );
    };

    4.3 DownloadTool: Use the useFileDownload hook and call its download function when the user activates the control. Add a download button so the user can save the PDF file.

    src/components/DownloadTool.jsx
    import { DownloadOutlined } from "@ant-design/icons";
    import { Button, Tooltip } from "antd";
    import { useFileDownload } from "@react-pdf-kit/viewer";
    export const DownloadTool = () => {
    const { download } = useFileDownload();
    return (
    <Tooltip title="Download file">
    <Button
    type="text"
    size="small"
    icon={<DownloadOutlined />}
    onClick={download}
    aria-label="Download file"
    />
    </Tooltip>
    );
    };

    4.4 PrintTool: Use the usePrintContext hook and call its print function on click. Add a print button so the user can open the browser print dialog.

    src/components/PrintTool.jsx
    import { PrinterOutlined } from "@ant-design/icons";
    import { Button, Tooltip } from "antd";
    import { usePrintContext } from "@react-pdf-kit/viewer";
    export const PrintTool = () => {
    const { print } = usePrintContext();
    return (
    <Tooltip title="Print">
    <Button
    type="text"
    size="small"
    icon={<PrinterOutlined />}
    onClick={print}
    aria-label="Print"
    />
    </Tooltip>
    );
    };

    4.5 SearchTool: Use the useSearchContext hook for the search query and match navigation. Add an Input for the search term, previous and next match buttons, and a short counter showing the current match index and total (for example 2 / 5).

    src/components/SearchTool.jsx
    import { CaretDownOutlined, CaretUpOutlined, SearchOutlined } from "@ant-design/icons";
    import { Button, Input, Space, Tooltip, Typography } from "antd";
    import { useSearchContext } from "@react-pdf-kit/viewer";
    export const SearchTool = () => {
    const { search, setSearch, prevMatch, nextMatch, totalMatches, currentMatchPosition } =
    useSearchContext();
    const handleSearch = (e) => {
    setSearch(e.target.value);
    };
    return (
    <Space size="small" align="center">
    <Input
    value={search}
    onChange={handleSearch}
    size="small"
    placeholder="Search"
    variant="outlined"
    prefix={<SearchOutlined style={{ color: "var(--ant-color-text-tertiary)" }} />}
    style={{ width: 180 }}
    aria-label="Search"
    />
    <Tooltip title="Previous match">
    <Button
    type="text"
    size="small"
    icon={<CaretUpOutlined />}
    onClick={prevMatch}
    aria-label="Previous match"
    />
    </Tooltip>
    <Tooltip title="Next match">
    <Button
    type="text"
    size="small"
    icon={<CaretDownOutlined />}
    onClick={nextMatch}
    aria-label="Next match"
    />
    </Tooltip>
    <Typography.Text type="secondary" style={{ minWidth: 36 }}>
    {currentMatchPosition} / {totalMatches}
    </Typography.Text>
    </Space>
    );
    };
  5. (Optional) You may add a small module (for example src/lib/const.ts) for shared layout or style constants that you reuse across the toolbar or other React PDF viewer components.

    src/lib/const.js
    export const CENTER_ALIGN_STYLE = { display: "flex", alignItems: "center" };

An image of create your own toolbar with Ant Design

Notes

  • Use RPConfig at the app root and RPProvider with a PDF src.
  • Keep CustomHorizontalBar (and all hook-based toolbar pieces) inside the same RPProvider that renders RPPages for that document.
  • Implement each action as a small component that uses exactly one viewer hook (useZoomContext, usePaginationContext, useFileDownload, usePrintContext, useSearchContext).
  • useSearchContext depends on the loaded PDF, until the document is ready match counts may be zero.