@ui-registries/pdf

Theming

Customize colors, spacing, typography, and more with the Tailwind provider.

Document theme

Pass your theme variables to <Document theme>. Without a theme, components use the defaults.

tsx
import { Document, Page, Text } from "@ui-registries/pdf";
<Document theme={{ "--color-primary": "#0073e6" }}>  <Page className="p-12">    <Text className="text-primary">Uses the custom theme</Text>  </Page></Document>

Tailwind Provider

<Tailwind theme> does the same thing as a standalone provider, for example to theme only part of a document.

Light / Dark Mode

@ui-registries/pdf does not detect or manage color schemes. The semantic tokens (like primary, muted-foreground, etc.) ship with light-theme defaults, but it's your app's responsibility to pass the right theme variables based on the current mode.

tsx
const lightTheme = {  "--color-background": "#ffffff",  "--color-foreground": "#0a0a0a",  "--color-primary": "#171717",  "--color-primary-foreground": "#fafafa",};
const darkTheme = {  "--color-background": "#0a0a0a",  "--color-foreground": "#fafafa",  "--color-primary": "#fafafa",  "--color-primary-foreground": "#0a0a0a",};
function MyDocument({ colorScheme }: { colorScheme: "light" | "dark" }) {  const theme = colorScheme === "dark" ? darkTheme : lightTheme;
  return (    <Tailwind theme={theme}>      <Document>        <Page className="p-12 bg-background">          <Text className="text-foreground">Adapts to color scheme</Text>        </Page>      </Document>    </Tailwind>  );}

If your app already has a theme system (shadcn, next-themes, etc.), read the current resolved values and forward them to <Tailwind theme={...}>.

Custom Theme

Pass a theme prop with CSS-variable-style keys to customize the design tokens. Custom values are merged with defaults — you only need to specify what you want to override.

tsx
<Tailwind theme={{  "--color-brand": "#0073e6",  "--color-brand-light": "#e6f0ff",  "--text-tiny": 5,  "--spacing": 4,           // change base unit (default: 3pt)  "--radius-pill": 50,}}>  <Document>    <Page className="p-12">      <Block className="bg-brand-light p-6 rounded-pill">        <Text className="text-tiny text-brand">Custom themed</Text>      </Block>    </Page>  </Document></Tailwind>

Theme Variables

Theme variables follow the Tailwind v4 CSS variable convention: --{category}-{name}: value.

Colors — --color-{name}

Add or override any color. The name becomes usable in bg-, text-, border-, and decoration- utilities.

tsx
theme={{  "--color-brand": "#0073e6",  "--color-brand-light": "#e6f0ff",  "--color-success": "#16a34a",}}// → bg-brand, text-brand-light, border-success

Colors can be hex, rgb, rgba, hsl, or oklch. OKLCH values are automatically converted to hex/rgba for PDF compatibility.

Spacing — --spacing

Override the base spacing unit. Default is 3 (3pt = 4px). All spacing utilities (p-, m-, gap-, w-, h-, etc.) scale from this base.

tsx
theme={{ "--spacing": 4 }}// p-4 = 16pt instead of 12pt

Spacing Steps — --spacing-{n}

Override individual spacing steps:

tsx
theme={{ "--spacing-18": 72 }}// p-18 = 72pt

Font Sizes — --text-{name}

Add or override named font sizes (in pt):

tsx
theme={{  "--text-tiny": 5,  "--text-display": 48,}}// → text-tiny (5pt), text-display (48pt)

Border Radius — --radius-{name}

tsx
theme={{  "--radius-pill": 50,  "--radius-DEFAULT": 6,     // changes what `rounded` resolves to}}

Font Family — --font-{name}

Override or add font families:

tsx
theme={{  "--font-sans": "Inter",  "--font-display": "Playfair Display",}}// → font-sans (Inter), font-display (Playfair Display)

Defaults: sans → Helvetica, serif → Times-Roman, mono → Courier.

Font Weight — --font-weight-{name}

tsx
theme={{ "--font-weight-black": 950 }}// → font-black (950)

Line Height — --leading-{name}

tsx
theme={{ "--leading-extra": 3 }}// → leading-extra (3)

Letter Spacing — --tracking-{name}

tsx
theme={{ "--tracking-extra": 2 }}// → tracking-extra (2pt)

Wildcard Resets

Use "initial" to clear all defaults for a category before adding your own:

tsx
<Tailwind theme={{  "--color-*": "initial",           // remove ALL default colors  "--color-black": "#000000",       // add back only what you need  "--color-white": "#ffffff",  "--color-brand": "#0073e6",}}>

Available wildcards:

VariableResets
--*Everything (colors, spacing, font sizes, radius, weights, etc.)
--color-*All colors
--text-*All font sizes
--radius-*All border radii
--spacing-*All spacing steps
--font-*All font families
--font-weight-*All font weights
--leading-*All line heights
--tracking-*All letter spacings
--opacity-*All opacity values

useTw() Hook

Access the current tw engine inside custom components:

tsx
import { useTw } from "@ui-registries/pdf";
function Badge({ label, variant }: { label: string; variant: "default" | "destructive" }) {  const tw = useTw();
  const baseStyles = tw("px-2 py-0.5 rounded-sm text-xs font-medium");  const variantStyles = variant === "destructive"    ? tw("bg-destructive text-destructive-foreground")    : tw("bg-primary text-primary-foreground");
  return (    <Block style={[baseStyles, variantStyles]}>      <Text>{label}</Text>    </View>  );}

The hook returns the themed tw function from the nearest <Tailwind> provider, or the default tw if none is present.

Standalone tw Engine

Use the tw engine outside of React components:

ts
import { createTw, tw, resolveTheme } from "@ui-registries/pdf";

A dedicated @ui-registries/pdf/tw subpath is also available if you need the tw engine without any React dependency (e.g. in a Node script or worker).

createTw(vars?)

Create a tw function with an optional custom theme:

ts
const tw = createTw({  "--color-brand": "#0073e6",  "--text-tiny": 5,});
const styles = tw("p-4 bg-brand text-tiny");// { paddingTop: 12, paddingRight: 12, paddingBottom: 12, paddingLeft: 12,//   backgroundColor: "#0073e6", fontSize: 5 }

tw

Pre-created tw function with the default theme:

ts
import { tw } from "@ui-registries/pdf";
const styles = tw("flex flex-row gap-2 p-4");

resolveTheme(vars?)

Process theme variables and return the resolved theme object. Useful for inspecting what values the engine will use:

ts
const theme = resolveTheme({ "--color-brand": "#0073e6" });// {//   spacingBase: 3,//   spacing: { "0": 0, "px": 0.75, "1": 3, ... },//   fontSize: { xs: 9, sm: 10.5, base: 12, ... },//   colors: { "brand": "#0073e6", "red-500": "#ef4444", ... },//   ...// }