Styling

The designer renders inside Shadow DOM, so your page's CSS doesn't leak into it, and its CSS doesn't leak out. Three things are public, stable API for matching it to your application:

  1. the theme attribute: light, dark or auto;
  2. the --rd-* custom properties (design tokens), set on the report-designer element;
  3. the ::part() names of its main regions.

Anything else, such as internal class names, element structure and undocumented custom properties, is internal and can change in any release.

Themes#

<report-designer theme="auto" font-base-url="/rd-fonts/"></report-designer>
ValueBehavior
light (default)The light palette
darkThe dark palette
autoFollows the operating system's prefers-color-scheme, and switches live when the user changes it

The page being designed always stays white (--rd-page), as it will print.

Design tokens#

Override tokens on the element from your page's stylesheet. Styles on the host element win over the designer's defaults in every theme:

report-designer {
    --rd-accent: #0f4c81;                          /* buttons, selection, active tabs, focus ring */
    --rd-font: 'Segoe UI', system-ui, sans-serif;  /* UI font (not the document fonts) */
    --rd-radius: 4px;
}

/* Only in the dark theme (theme="dark") */
report-designer[theme='dark'] {
    --rd-panel: #101418;
    --rd-bg: #0b0e12;
}

/* theme="auto" while the system is dark */
@media (prefers-color-scheme: dark) {
    report-designer[theme='auto'] {
        --rd-panel: #101418;
    }
}

One brand color recolors everything. --rd-accent-hover, --rd-accent-soft and --rd-grid are derived from --rd-accent with color-mix() unless you override them, so report-designer { --rd-accent: #c2410c; } alone gives a consistent orange UI: buttons, hover states, selected rows, focus halos and the canvas grid.

The complete list, with the defaults of each theme:

TokenPurposeLightDark
--rd-fontUI font stack (toolbar, panels, dialogs; not document fonts)'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif
--rd-bgApplication background behind panels#f4f5f7#16181d
--rd-panelToolbar, side panels, dialogs and inputs#ffffff#1e2128
--rd-panel-2Secondary surfaces: panel headers, cards, hover fills#f8f9fb#252931
--rd-borderHairline borders and separators#e1e4ea#2f343e
--rd-border-strongHovered borders, scrollbar thumbs, dashed placeholders#c9ced8#3c4250
--rd-textPrimary text#1d2433#e6e8ee
--rd-mutedSecondary text: labels, hints, section titles#6b7385#9aa1b0
--rd-faintTertiary text: placeholders, rulers, counts#9aa1b0#6b7385
--rd-accentBrand/accent: primary button, selection, active tabs, focus ring#2f6fed#4c86ff
--rd-accent-hoverPrimary button hover (derived from --rd-accent by default)color-mix(in srgb, var(--rd-accent) 86%, #000)color-mix(in srgb, var(--rd-accent) 80%, #fff)
--rd-accent-softAccent tint: active toggles, selected rows, focus halo (derived from --rd-accent by default)color-mix(in srgb, var(--rd-accent) 12%, #fff)color-mix(in srgb, var(--rd-accent) 24%, #1e2128)
--rd-accent-textText on accent backgrounds#ffffff#ffffff
--rd-dangerErrors and destructive actions#d93a3a#f06464
--rd-canvasCanvas backdrop around the page#e7e9ee#111317
--rd-pagePaper color of the page on the canvas#ffffff#ffffff
--rd-band-stripBand label strips on the canvas#eef0f4#262a33
--rd-marginPage margin shading on the canvasrgba(30, 40, 60, 0.035)rgba(0, 0, 0, 0.05)
--rd-gridCanvas grid lines (derived from --rd-accent by default)color-mix(in srgb, var(--rd-accent) 9%, transparent)color-mix(in srgb, var(--rd-accent) 12%, transparent)
--rd-guideSmart-guide (snap) lines while dragging#ff2d8a#ff4f9f
--rd-shadow-lgElevation of dialogs, drawers, popovers and toasts0 12px 32px rgba(16, 24, 40, 0.18)0 12px 32px rgba(0, 0, 0, 0.55)
--rd-radiusCorner radius of buttons and controls6px6px

Parts#

Style a whole region with ::part(). Parts inside nested panels are re-exported to the report-designer element, so one selector reaches them:

/* A dark, branded toolbar */
report-designer::part(toolbar) {
    background: #0f172a;
    border-bottom-color: #0f172a;
}
report-designer::part(toolbar-button) {
    color: #cbd5e1;
}
report-designer::part(primary-button) {
    background: #f59e0b;
    color: #111827;
}

/* A softer canvas backdrop */
report-designer::part(canvas) {
    background: #eef2f7;
}
PartRegion
::part(toolbar)Top toolbar
::part(toolbar-title)The report icon, name and read-only badge at the left of the toolbar
::part(toolbar-logo)The report icon (replace it with your own through the `logo` slot)
::part(toolbar-name)The report name. Hide it when your app shows the name itself
::part(toolbar-button)Every icon button in the toolbar (also matches the Help button)
::part(primary-button)The "Preview PDF" button
::part(sidebar)Both side panels (left and right)
::part(sidebar-left)Left side panel (Insert / Fields / Layers)
::part(sidebar-right)Right side panel (Properties / Report)
::part(tabs)Tab strip at the top of each side panel
::part(tab)One tab in a tab strip
::part(insert-panel)Insert tab content (element palette)
::part(palette-tile)One element tile in the palette
::part(fields-panel)Fields tab content (data-contract tree)
::part(layers-panel)Layers tab content
::part(properties-panel)Properties tab content
::part(report-panel)Report tab content
::part(canvas)Canvas area (scrollable backdrop)
::part(page)The page sheet on the canvas
::part(statusbar)Bottom status bar
::part(modal)Modal dialogs (gallery, PDF import and preview)
::part(gallery)The "New from template" dialog
::part(import)The "Import PDF" dialog
::part(preview)The PDF preview dialog
::part(help-drawer)The help side drawer
::part(toast)Transient notifications

::part() selectors can't reach elements inside a part (no ::part(toolbar) button). Use the dedicated parts (toolbar-button, tab, palette-tile) or the tokens instead.

Recipes#

Hide the report name when your app shows it. If your page has its own header with the report's name, hide the designer's name and keep its icon:

report-designer::part(toolbar-name) {
    display: none;
}

::part(toolbar-title) hides the icon, the name and the read-only badge together.

The template still has a name. Keep your field as the source and apply it when you save, for example designer.addEventListener('save', (e) => store({ ...e.detail.template, name: nameField.value })). Don't assign designer.template on every keystroke: that loads the template again and clears the undo history.

Use your own icon. Put an image or SVG inside the element with slot="logo". It replaces the default icon and is fitted into a 26 × 26 px box (keeping its aspect ratio):

<report-designer>
    <img slot="logo" src="/assets/brand-mark.svg" alt="" />
</report-designer>

The icon is your own element in your page, so it follows your page's styles and Content Security Policy. Style the box around it with ::part(toolbar-logo), for example a background or rounded corners.

Match your app's brand and font.

report-designer {
    --rd-accent: #7c3aed;
    --rd-font: 'Inter', system-ui, sans-serif;
}

Follow your app's own dark mode switch (instead of the OS setting): set theme from your app's state, for example designer.setAttribute('theme', isDark ? 'dark' : 'light').

A compact, square look.

report-designer {
    --rd-radius: 2px;
}
report-designer::part(palette-tile) {
    border-radius: 2px;
}

Read-only template viewer with a quiet chrome.

report-designer[read-only]::part(toolbar) {
    background: var(--rd-panel-2);
}

Try overrides live in the Playground: open your browser's developer tools and add CSS rules for report-designer.