Themes and Export
Use this page when a visual system must travel beyond one chart. Start with
xy.theme() and reusable palette tokens, add light/dark host values, then pick
an export path based on whether the output can run a browser CSS cascade.
Use this page to:
- Set chart-wide colors and chrome. Start with the theme component →
- Build and reuse a semantic palette. Open the palette example →
- Understand which declaration wins. Review style resolution →
- Support the page's color mode. Review automatic dark mode →
- Use a brand font. Review custom-font behavior →
- Choose HTML, SVG, or PNG behavior. Compare output behavior →
If you are still choosing a finished visual, start with Examples. To adjust a single mark, axis, legend, tooltip, or annotation, use Customize Each Part. For density, uncertainty, facets, and renderer edge cases, continue to the Advanced Gallery.
Start with the theme component
Use xy.theme() when the value belongs to the chart rather than one specific
mark. Its named arguments are readable aliases for the standard tokens: for
example, plot_background writes --chart-bg, while grid_color writes
--chart-grid.
The preview separates two kinds of values:
plot_background,grid_color,axis_color, andtext_colorconfigure standard XY chrome throughxy.theme().- The chart class supplies neutral light and dark hex values for the demo surface and chrome. The area keeps one saturated rose stroke and matching 30%-to-transparent fade so the theme choices stay visually distinct.
- Axis components decide which chrome is drawn: both axes omit labels and tick marks, the x grid is disabled, and the y axis keeps only horizontal guides.
Keep a mark's stroke and fade stops on the same vivid hue:
Build a reusable palette
Application tokens are useful when several marks should move together. This
grouped column chart maps three semantic names to three colors; swapping the
values in style= restyles the whole preview without touching the marks.
Explicit numeric offsets and narrow columns leave a visible gap inside every
group.
Style resolution without surprises
Think from the narrowest styling surface to the broadest:
- Typed mark or axis props describe rendered geometry and paint.
- Component-local
style=customizes one legend, tooltip, modebar, or annotation label. - Chart
styles={slot: ...}andclass_names={slot: ...}apply a shared rule to that chrome slot. xy.theme()and chart-rootstyle=define chart-wide tokens and root appearance.- Host CSS supplies inherited defaults, application tokens, and color-mode values in a browser.
That list is a scope ladder, not one universal cascade. Marks and axes are painted geometry, while legends and tooltips are DOM chrome. When two declarations target the same property, use these concrete winner rules:
Component style= and chart styles= become inline DOM styles. The component
is merged last, so it wins for the same property. Classes and normal host CSS
remain ideal for shared or stateful styling, but they do not override an inline
declaration unless the host deliberately uses !important. A CSS variable is
resolved where it is used: color="var(--series-primary)" does not make host
CSS stronger than a chart-local --series-primary declaration.
For example, the mark is violet, the legend is compact, and the chart-root token is amber:
Use typed props for readable geometry, component styles for one-off chrome, chart slots for reusable chrome rules, and theme tokens for values that should move together across the whole chart.
Where should a token be set?
Token reference
You can define application-specific variables such as --chart-accent and use
them from mark styles. XY validates the var(...) shape, then the browser
resolves it against the chart root on each render.
Cascading from host CSS
In Reflex, resolve reactive theme choices into ordinary classes, styles, or CSS variables. XY does not duplicate Reflex conditions or application state.
What survives each output
Browser-backed output can run a CSS cascade; browser-free output cannot. Put export-critical paint and tokens on the chart itself, then use host CSS for browser-only adaptation.
“Supported static chrome fields” means options the SVG/native renderer owns,
such as axes and the built-in legend. It does not mean arbitrary DOM CSS or
Tailwind classes are evaluated without a browser. Browser-only color
expressions may also need a concrete fallback for SVG or native PNG:
var(--accent, #8e51ff).
The toolbar’s client PNG and SVG actions are a separate browser snapshot path:
they read the live chart’s computed tokens and font styles, so inherited host
styling is captured at download time. Python to_svg() and native to_png()
never inspect the host page. Chromium to_png() renders standalone HTML, so
pass any required author rules explicitly with custom_css.
For exporter selection, engine arguments, and complete code examples, see Display and Export.
Custom fonts and export limitations
Browser charts inherit fonts from the chart root. Load the font in the host
application first, then set font_family through chart style= or apply a
class that defines font-family. The live example uses a system serif so it
does not depend on a network font; replace that stack with the family your host
loads.
For a downloaded or self-hosted font, define @font-face in the Reflex
application's global stylesheet and use the same family on the chart:
Tailwind users can apply a configured font utility through class_name in the
same way. XY does not download, register, or rewrite font files itself.
Standalone HTML and Chromium PNG accept the font declaration through
custom_css. Embed the font as a data URL when the HTML file must remain fully
portable; an ordinary URL still depends on that resource being reachable.
Automatic dark mode for the toolbar
The interactive toolbar (modebar) has no colored default a page can show
through, so it reads the light/dark state straight from your page: when a
.dark class is present on the chart root or any ancestor — the convention
Reflex (next-themes), Radix Themes, and Tailwind all set on the root <html>
element — its background, border, and shadow switch to a dark palette. Icon
color already follows the inherited text color, so the toolbar stays readable in
both modes with no configuration. An explicit .light class (or no class at
all) keeps the light palette.
These neutral colors are built into every toolbar; an app does not need to map
them to its own secondary palette. A --chart-modebar-bg,
--chart-modebar-active, or --chart-modebar-focus value you set through
theme(), chart style=, or a host stylesheet still wins in either mode.
The toolbar's focus ring resolves in three steps: --chart-modebar-focus
first, then --chart-focus, then the built-in scheme-aware neutral. So an app
that themes focus once with --chart-focus gets one ring color across the plot
canvas and the toolbar, and --chart-modebar-focus exists to break that tie
when the toolbar needs its own.
Dark mode in a standalone export
Standalone HTML and Chromium PNG use the browser cascade. Native PNG and SVG
can resolve variables declared on the chart's own style/theme plus
var(--name, fallback) values, but they cannot see an external host page's
stylesheet. Put export-critical tokens on the chart itself when output must be
identical outside the browser host.
API Reference
xy.theme
Configure chart theme tokens.
Props
| Prop | Type | Description |
|---|---|---|
style | Optional[dict[str, StyleValue]] | Base chart style overrides. |
background | Optional[StyleValue] | Figure background color — paints the whole chart card including margins, title, and tick labels (matplotlib's ``figure.facecolor``). The plot rect shows through unless ``plot_background`` sets it separately. |
plot_background | Optional[StyleValue] | Plot-area background color — the data rect only (matplotlib's ``axes.facecolor``). |
grid_color | Optional[StyleValue] | Grid-line color. |
axis_color | Optional[StyleValue] | Axis-line and tick color. |
text_color | Optional[StyleValue] | Default chart text color. |
crosshair_color | Optional[StyleValue] | Hover crosshair color. |
selection_color | Optional[StyleValue] | Selection-outline color. |
selection_fill | Optional[StyleValue] | Selection-region fill color. |
**tokens | StyleValue | Additional supported theme tokens. |