Categorical, sequential, semantic, and diverging chart color palettes
The data visualization color palettes are based on Pluma's color palette, and are dark-mode aware. They are designed to be accessible, consistent, and predictable across a variety of chart types and data representations, ensuring that colors convey meaning effectively while maintaining visual harmony.
The palettes are categorized into four main types:
Each palette and color is available as a color token, with dataViz-prefixed names. For convenience, the @customerio/pluma-components/data-viz package exports utilities to retrieve the right palette subset for your needs. The utilities are:
defaultColor(): Returns the default color descriptor for single-series charts.categorical(n): Returns the first n slots of the categorical palette (1 to 16).sequential(variant, n): Returns a subset of the sequential palette for the specified variant (e.g., 'blue', 'teal') and count n (1 to 9).semantic(role, n): Returns a subset of the semantic palette for the specified role (e.g., 'success', 'caution') and count n (1 to 9).diverging(palette): Returns the full diverging palette for the specified palette (e.g., 'temperature', 'neutral', 'cool').Each returns an array of DataVizColor descriptors (a single one for defaultColor), which is an object with the following keys:
type: The palette type ('categorical', 'sequential', 'semantic', or 'diverging').name: A unique name for the color, derived from its token name.
token: The CSS variable reference for the color (e.g., var(--pluma-dataViz-categorical-1)).tokenHover: The CSS variable reference for the hover state of the color (e.g., var(--pluma-dataViz-categorical-1-hover)).tokenText: The CSS variable reference for readable text in the color's hue: its scope's text color (e.g., the color.scope.teal.text token for categorical-1, color.scope.success.text for a success step). Use it for a label or caption that belongs to the color, since a data-viz step is chosen to read as a mark, not as text. It pairs with the hue rather than the step, so every step of one ramp shares it; a diverging palette's midpoint pairs with neutral text. It is optional on a DataVizColor you build yourself; without it, chart text in that color is written in its token.The count argument in each function is optional - if omitted, the full palette is returned. More details on the functions are available below in their respective sections.
defaultColor() (categorical slot 1).categorical in slot order. For longer series, we recommend applying additional encodings (line style, dash, dot, or pattern) to avoid color confusion. Even within the available palette, use those additional encodings when the chart must remain readable without color. Looping the categorical palette is not recommended, as it can lead to misinterpretation of series identity, but is possible as a last resort.semantic role palette with the subset matching the series count.sequential palette -- the full set for smooth fills, or a subset for identifiable bins.diverging palette.These are best used for unrelated series, or when you want to distinguish between different categories without implying order, magnitude, or relation. The palette should be used in the provided order, as the colors are designed to be visually distinct and harmonious when used together.
dataViz-categorical-{n}categorical(n) returns the first n slots of the categorical palette, where n can be any integer from 1 to 16. If n is omitted, the full palette is returned. The main gray is deliberately the final slot so chromatic choices are exhausted first.
Sequential palettes are best for ordered data, where color intensity represents magnitude, or for representing related series.
Every primitive color family has a matching sequential palette with 9 distinct steps. For each palette, smaller subsets with fewer steps are available, which are designed to be visually distinct and harmonious at every count. Most palettes use step 5 for one series and spread across steps 1, 5, 7, and 9 for two to four series. Yellow instead uses step 3 and spreads across steps 1, 3, 5, and 7, keeping caution data recognizably yellow. In light mode, steps 7 through 9 use the darker 800, 900, and 950 primitive colors. Counts above 4 fill additional steps. Use the subset for the intended series count rather than trimming from the full set.
Dark mode reverses the primitive strength progression so step 1 stays nearest the surface and step 9 stays furthest from it in both themes. Hover colors move one primitive step toward greater emphasis: darker in light mode and lighter in dark mode.
dataViz-sequential-blue-{n}dataViz-sequential-brown-{n}dataViz-sequential-fuchsia-{n}dataViz-sequential-gray-{n}dataViz-sequential-green-{n}dataViz-sequential-lime-{n}dataViz-sequential-olive-{n}dataViz-sequential-orange-{n}dataViz-sequential-pink-{n}dataViz-sequential-red-{n}dataViz-sequential-rose-{n}dataViz-sequential-silver-{n}dataViz-sequential-sky-{n}dataViz-sequential-teal-{n}dataViz-sequential-verdant-{n}dataViz-sequential-violet-{n}dataViz-sequential-yellow-{n}Sequential palettes can be accessed using the sequential(variant, n) function, where variant is the name of the palette (e.g., 'blue', 'teal') and n is the number of steps desired (1 to 9). If n is omitted, the full palette is returned.
The semantic palettes are aliases of the sequential ones, but with a role that conveys meaning. Use these instead of sequential palettes when the series' are associated with a specific meaning. The roles are:
neutral (gray): for series that are neutral or non-critical, such as background or reference data.information (blue): for series that convey information or status, such as notifications or updates.success (green): for series that indicate success or positive outcomes.caution (yellow): for series that indicate caution or warning.critical (red): for series that indicate critical or error states.dataViz-semantic-neutral-{n}dataViz-semantic-information-{n}dataViz-semantic-success-{n}dataViz-semantic-caution-{n}dataViz-semantic-critical-{n}Semantic palettes can be accessed using the semantic(role, n) function, where role is the semantic role (e.g., 'success', 'caution') and n is the number of steps desired (1 to 9). If n is omitted, the full palette is returned.
Diverging palettes also convey meaning, but are designed for data that diverges around a central point, or for highlighting differences between two extremes. Each palette provides 15 steps: 7 on either side of a light midpoint at step 8.
dataViz-diverging-cool-{n}dataViz-diverging-neutral-{n}dataViz-diverging-temperature-{n}Diverging palettes can be accessed using the diverging(palette) function, where palette is the name of the diverging palette (e.g., 'temperature', 'neutral', 'cool'). The full diverging palette is returned.
Every item returned by the utility functions carries a tokenHover, so a series can swap to color.tokenHover on interaction. The hover always moves in the emphasis direction -- darker in light mode, lighter in dark mode -- for every step of every palette, so lines, bars, and binned encodings all hover the same way.
While we recommend using typical legend-style labels for chart series (a colored box with text beside it), we may sometimes reach to Badge components for additional visual representation of items falling into a particular category. The Badge itself doesn't come with color tokens to match to chart series exactly, but they can be customized on a case-by-case basis using CSS and color mixing.
This recipe recommends:
background-color, mix the chart color 20% with the page background (lightens in light mode, darkens in dark mode)color, mix the chart color 40% with the default text color (darkens in light mode, lightens in dark mode)This produces Badges that are visually distinct, but still clearly associated with the chart color. The recommended mix percentages are designed to maintain accessibility (APCA and WCAG) in both light and dark modes.