# Theming and customization

Source: https://sdk.pdf.net/docs/v1/guides/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](https://sdk.pdf.net/docs/v1/guides/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](https://sdk.pdf.net/docs/v1/guides/theming-and-customization#custom-components). |

## Styleable elements [#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](https://sdk.pdf.net/docs/v1/reference/useDocumentSearch). |

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 [#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 [#putting-it-together]

```tsx
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 [#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](https://sdk.pdf.net/docs/v1/reference/WidgetOverlay).                                        |
| `widgetPreview` | Replaces the box following the cursor while the `addWidget` interaction tool is active. Receives the props of [WidgetPreview](https://sdk.pdf.net/docs/v1/reference/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:

```tsx
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.

