Skip to content

Building reports

Themes & styling

Themes are CSS stylesheets driven by a set of CSS variables. Three styling levels - theme, report, page - each in its own CSS layer.

A theme in Golden Reports is a CSS stylesheet bound to one or more reports. Its primary purpose is to configure the platform's set of CSS custom properties (--gr-*) - the variables that drive how built-in blocks and base styles render. Set the variables and every block in every bound report picks up the change without any per-block work.

You can also write any CSS you want in a theme stylesheet (own selectors, custom classes, helper utilities). But to customize the look of existing blocks and base styles, the variables are almost always the right path - they're the surface the platform's components are built against.


Three levels of styling

Styling composes from three levels, each defined separately and each living in its own CSS cascade layer. The order from least to most specific is:

  1. Theme. Workspace-wide stylesheet bound to a report from the Visual panel. This is the foundation - everything else inherits from it.
  2. Report. CSS that applies to one specific report, overriding the theme for that report only. Authored in the report editor's styling section.
  3. Page. A printed report can contain multiple pages (front cover, content body, back cover); each page can carry its own CSS that overrides the report and theme for just that page. For dashboard or embedded reports you'll usually only have a first page, so the page layer is rarely needed there.

Because each level is its own CSS layer (declared with @layer theme, report, page), the cascade order is deterministic: page overrides report, report overrides theme, regardless of selector specificity. You don't need to write !important or counter-engineer specificity to override an inherited value - the layer order does that for you.

If a level doesn't define a property, the next level up handles it. Reset a page-level rule and the report-level rule takes over; reset that and the theme's value applies.


How a theme stylesheet is structured

A typical theme stylesheet has three or four blocks:

.light {
  /* Color variables for light color scheme */
  --gr-color-surface: #f8fafc;
  --gr-color-text-primary: #0f172a;
  --gr-color-accent: #0f3d6b;
  /* ... */
}

.dark {
  /* Same variables, dark values */
  --gr-color-surface: #0f172a;
  --gr-color-text-primary: #e2e8f0;
  --gr-color-accent: #3b82f6;
  /* ... */
}

:root {
  /* Everything else - typography, spacing, radii, transitions, body layout */
  --gr-font-family-base: "Inter", system-ui, sans-serif;
  --gr-spacing-4: 1rem;
  --gr-radius-base: 6px;
  /* ... */
}

@media print {
  .light, .dark {
    /* Print-specific overrides - usually force white bg, black text, no shadows */
    --gr-color-surface: #ffffff;
    --gr-color-text-primary: #000000;
    --gr-shadow-base: none;
  }
}

The .light and .dark selectors scope variables to the report's active color scheme. Variables that aren't color-scheme dependent (fonts, spacing, radii) live under :root. The @media print block lets a printed export look different from on-screen rendering - typically simpler.

The built-in themes (Midnight, Corporate, Warm Earth, Ocean, Rose, Ink, Carbon, Evergreen) are the best reference. Reading their source is the fastest way to internalize the variable surface.


The variable surface

The platform exposes a stable set of CSS variables. Setting any of them in a theme overrides the default. Anything you don't override falls back to the platform's defaults.

Colors (light/dark scoped)

Surface and background:

  • --gr-color-surface - main report surface (page body background).
  • --gr-color-surface-alt - secondary surfaces (alternate rows, subdued panels).
  • --gr-color-surface-elevated - cards, modals, popovers.
  • --gr-color-background - the canvas behind the report.

Text:

  • --gr-color-text-primary - body text.
  • --gr-color-text-secondary - meta and supporting text.
  • --gr-color-text-muted - placeholders, captions, very low emphasis.
  • --gr-color-text-inverse - text on colored fills (e.g., on accent).

Accent (your brand color):

  • --gr-color-accent, --gr-color-accent-hover, --gr-color-accent-text.

Status:

  • --gr-color-success, --gr-color-warning, --gr-color-danger, --gr-color-info.

Borders:

  • --gr-color-border - default borders and dividers.
  • --gr-color-border-light - subdued separators.

Chart series (8 numbered colors, used by chart blocks):

  • --gr-chart-color-1 through --gr-chart-color-8.

Shadows (light/dark scoped)

  • --gr-shadow-sm, --gr-shadow-base, --gr-shadow-md, --gr-shadow-lg.

Typography (scheme-agnostic)

Font families:

  • --gr-font-family-base - body text.
  • --gr-font-family-heading - headings.
  • --gr-font-family-mono - code, identifiers.

Font sizes (eight steps):

  • --gr-font-size-xs, --gr-font-size-sm, --gr-font-size-base, --gr-font-size-lg, --gr-font-size-xl, --gr-font-size-2xl, --gr-font-size-3xl, --gr-font-size-4xl.

Weights:

  • --gr-font-weight-normal, --gr-font-weight-medium, --gr-font-weight-semibold, --gr-font-weight-bold.

Line heights:

  • --gr-line-height-tight, --gr-line-height-base, --gr-line-height-relaxed.

Custom fonts are uploaded as Assets and referenced from the theme stylesheet by URL.

Spacing scale (scheme-agnostic)

A numbered scale used for paddings, gaps, gutters, and margins throughout the platform:

  • --gr-spacing-1, --gr-spacing-2, --gr-spacing-3, --gr-spacing-4, --gr-spacing-5, --gr-spacing-6, --gr-spacing-8, --gr-spacing-10, --gr-spacing-12.

Borders and radius (scheme-agnostic)

  • --gr-border-width - default border width.
  • --gr-radius-sm, --gr-radius-base, --gr-radius-lg, --gr-radius-xl - corner radius scale.

Transitions (scheme-agnostic)

  • --gr-transition-fast, --gr-transition-base, --gr-transition-slow.

Report body layout (scheme-agnostic)

  • --gr-body-max-width, --gr-body-margin, --gr-body-padding, --gr-body-bg, --gr-body-shadow, --gr-body-radius.

These shape the report's outer container. They're useful when you want, say, a card-like report on a canvas instead of edge-to-edge content.


Applying a theme

  1. Open the report in the editor.
  2. Open the Visual panel in the left rail.
  3. Pick a theme from the dropdown. The design surface updates immediately.

To change the workspace default theme (applied to new reports), set it in Manager → Themes → Workspace defaults.


Per-block overrides

Sometimes a single block needs to stand out - a KPI on a financial report, a "PAID" stamp on an invoice. Select the block, open the Styles tab, and set any property explicitly. The chip next to each style property tells you whether it's:

  • Inherited (from the theme),
  • Inline (set on this block), or
  • Computed (from a Liquid binding).

Per-block styles are emitted into the report layer (or, if the block lives on a page with its own CSS, the page layer) - so they win over the theme automatically. Click the chip and choose "Reset" to drop back to the inherited value.

Conditional styles

Per-block styles can be bound to Liquid expressions. Example: highlight a table row when order.status == 'overdue':

Row background-color: {% if row.status == 'overdue' %}var(--gr-color-danger){% else %}var(--gr-color-surface){% endif %}
Previous
Liquid templating