Skip to content

Theming

The interface is styled with CSS variables set on its root element (.ar-root). There are three ways to set them.

import { DARK_THEME, ReportViewer } from '@ariana-reports/react';
<ReportViewer theme={DARK_THEME} template={template} data={data} />
<ReportViewer theme={{ primary: '#6750a4', radius: 12, fontFamily: 'Inter, sans-serif' }} template={template} data={data} />
Theme property CSS variable Used for
primary, onPrimary --ar-primary, --ar-on-primary selection, focus rings, active buttons
background --ar-bg workspace behind pages
surface, surfaceVariant --ar-surface, --ar-surface-2 toolbars, panels, section headers
inputBackground, border --ar-input-bg, --ar-border inputs and dividers
text, textMuted, danger --ar-text, --ar-muted, --ar-danger text, labels, errors
radius, fontFamily, fontSize --ar-radius, --ar-font, --ar-font-size shape and typography
bandColor --ar-band-color default band caption color in the designer
mode color-scheme light or dark: native scrollbars and pickers

themeFromMui(theme) converts a MUI theme, so the report UI follows your palette and dark mode. See Material UI.

Set the variables in a rule for .ar-root. The defaults have zero specificity, so your rule wins whatever the order of the stylesheets:

.ar-root {
--ar-primary: #6750a4;
--ar-surface: #fffbfe;
}
[data-theme='dark'] .ar-root {
--ar-bg: #1c1b1f;
--ar-surface: #2b2930;
--ar-text: #e6e1e5;
color-scheme: dark;
}

The variables must be set on .ar-root itself (not on a parent). All class names start with ar- if you want to override individual rules.

Pages and the design surface are drawn like paper, with the template’s own colors, in every theme. Theming only changes the application chrome around them.

viewer-theme.tsx
import { useState } from 'react';
import { DARK_THEME, ReportViewer, themeFromMui } from '@ariana-reports/react';
import { salesData, salesTemplate } from './report-data';
// Any object shaped like a Material UI theme works, so in a MUI app pass useTheme() directly.
const grape = themeFromMui({
palette: { mode: 'light', primary: { main: '#7b1fa2' }, background: { default: '#f3e5f5', paper: '#ffffff' } },
shape: { borderRadius: 14 },
});
const themes = { default: undefined, dark: DARK_THEME, grape } as const;
export default function ViewerTheme() {
const [name, setName] = useState<keyof typeof themes>('grape');
return (
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<label style={{ padding: 8, background: '#fff', font: '13px system-ui' }}>
Theme{' '}
<select value={name} onChange={(e) => setName(e.target.value as keyof typeof themes)}>
{Object.keys(themes).map((t) => (
<option key={t}>{t}</option>
))}
</select>
</label>
<div style={{ flex: 1, minHeight: 0 }}>
<ReportViewer template={salesTemplate} data={salesData} theme={themes[name]} zoomMode="fitWidth" showIssues />
</div>
</div>
);
}