Theming and customization
The SDK renders its UI unstyled on purpose: your application's design system supplies the look. All visual customization goes through the theme configuration of PdfProviders (memoized like any other configuration, see Getting started):
| Option | Type | What it does |
|---|---|---|
viewportPadding | number | number[] | The gap between the pages and the viewport edges, in pixels. Follows the CSS padding shorthand. |
classNames | Record<StyleKeys, string> | Class names appended to the elements the SDK renders. |
styles | Record<StyleKeys, CSSProperties> | Inline styles applied to the elements the SDK renders. |
components | { pageOverlay, widgetOverlay, widgetPreview } | Your components, replacing built-in ones or added to every page. See Custom components. |
Styleable elements
classNames and styles share the same keys, one per element the SDK renders:
| Key | Element |
|---|---|
scrollViewport | The viewport: the scrollable, zoomable area holding the pages. |
pagesContainer | The element laying out the pages inside the viewport. |
page | One page. |
pageCanvas | The canvas rendering a page's content. |
rubberbandSelection | The rectangle drawn while drag-selecting blocks. |
resizable | The frame around a selected block. |
resizableHandle | A resize handle on that frame. |
widgetOverlay | The interactive overlay over a form widget. |
widgetInput | The input element inside a text or choice widget. |
widgetSignature | The content of a signature widget. |
widgetSignatureHint | The hint inside an empty signature widget. |
widgetPreview | The preview box while placing a new widget. |
imagePreview | The preview shown while placing an image. |
searchMatch | A text match highlighted by document search. |
The searchMatch element is part of the text layout, so style it with paint properties only, such as background or color: a padding, margin, or border moves the text. Give lengths units ('4px', not 4). The active match carries a data-active attribute, so a classNames.searchMatch class can style it apart with a [data-active] selector.
CSS variables
The viewport element defines CSS variables that the selection and widget visuals read. Override them through styles.scrollViewport, or in CSS through your classNames.scrollViewport class:
| Variable | Controls |
|---|---|
--selection-color | The selection outlines, handles, and the rubberband. |
--selection-handle-fill-color | The fill of the resize handles. |
--outline-width | The width of the selection outline. |
--outline-offset | The offset of the selection outline from the block. |
--widget-overlay-background | The background of the interactive widget overlay. |
--widget-focused-overlay-background | The background of the focused widget's overlay. |
--search-match-background | The highlight of a search match. |
--search-match-active-background | The highlight of the active search match. |
There are also --outline-touch-drag-* and --touch-indicator-* variables tuning the outline and the touch indicator during touch interactions.
Putting it together
import { Config, PdfProviders } from '@sdk-pdf/react'
const theme: Config['theme'] = {
viewportPadding: [24, 16],
classNames: { scrollViewport: 'my-viewport', page: 'my-page' },
styles: {
scrollViewport: { '--selection-color': 'rebeccapurple' } as React.CSSProperties,
resizableHandle: { borderRadius: '50%' },
},
}
export function App() {
return (
<PdfProviders theme={theme}>
<DocumentLoader />
</PdfProviders>
)
}Custom components
theme.components replaces parts of the SDK UI with your own components:
| Key | What it does |
|---|---|
widgetOverlay | Replaces the highlight drawn over a form widget. Receives the props of WidgetOverlay. |
widgetPreview | Replaces the box following the cursor while the addWidget interaction tool is active. Receives the props of WidgetPreview. |
pageOverlay | Adds your component on top of every visible page, covering it. Receives the page id, its index, and a class name that positions it over the page. |
Each value is a component or a React element. A replacement receives the same props as the built-in component, including the className and style from classNames and styles. The built-in components are exported, so a replacement can wrap them instead of starting from scratch:
import { Config, PageOverlayProps, WidgetOverlay, useWidgetById } from '@sdk-pdf/react'
import { ComponentProps } from 'react'
// Marks the required form fields while keeping the built-in highlight.
function RequiredFieldOverlay(props: ComponentProps<typeof WidgetOverlay>) {
const widget = useWidgetById(props.widgetId)
return <WidgetOverlay {...props} data-required={widget?.isRequired || undefined} />
}
// Shows the page number over each page.
function PageNumberOverlay({ pageIndex, className }: PageOverlayProps) {
return (
<div className={className}>
<span className="page-number">{pageIndex + 1}</span>
</div>
)
}
const theme: Config['theme'] = {
viewportPadding: 24,
components: { widgetOverlay: RequiredFieldOverlay, pageOverlay: PageNumberOverlay },
}Like the rest of the configuration, keep the theme object stable between renders: define it outside the component or memoize it.