PlumaProvider provides context to all Pluma components. More specifically, it:
It is required to render PlumaProvider at the root of your app.
A theme object provides all the tokens and styles for a theme. It can be passed to PlumaProvider
as the theme prop:
The theme object must implement the PlumaTheme or PartialPlumaTheme type, both of which are based on the token output generated from our base tokens.
PlumaProvider will render a div element and attach the theme's class name to it,
which adds all the theme's CSS variables to that container.
If you need to add additional classes to that element,
add them to PlumaProvider, which will forward them to the div:
If you don't need to render the theme container - for example, when using Pluma Components inside a
microfrontend where the root app already has a theme - you can prevent PlumaProvider from
rendering it with the shouldRenderContainer argument:
Note that it is still recommended to provide a theme, even to a PlumaProvider within a nested
microfrontend. You should retrieve the theme from the root app and pass it into the microfrontends, in case
any code or component needs to access the theme's variables via context.
In addition to the explicit theme prop, PlumaProvider accepts a colorScheme prop that picks
between light and dark tokens at runtime. It accepts:
'light' (default) — apply the light tokens.'dark' — apply the dark tokens.'auto' — follow the user's system preference via prefers-color-scheme. The Provider listens
for changes and updates dynamically.To use colorScheme you also pass themes — an object with light and/or dark theme objects.
The Provider picks the matching one based on the resolved scheme:
themes is consumer-supplied so callers that always pass their own theme don't pull the
canonical light/dark theme CSS into their bundle. Import the canonical themes from
@customerio/pluma-components/css if you want the standard light/dark behavior.
When the theme prop is provided, colorScheme and themes are ignored — theme always wins as
an explicit override.
Three contexts are exposed for descendants:
PlumaThemeContext (usePlumaTheme() in React, @consume(PlumaThemeContext) in Ember) — the
effective theme object.PlumaColorSchemeContext (usePlumaColorScheme() / @consume(PlumaColorSchemeContext)) — the
resolved scheme, always 'light' or 'dark'. When colorScheme is 'auto', this is the
system-resolved value. Use this for conditional logic that needs a concrete scheme.PlumaColorSchemePreferenceContext (usePlumaColorSchemePreference() /
@consume(PlumaColorSchemePreferenceContext)) — the unresolved preference
('auto' | 'light' | 'dark'). Used by components like Image that need to
decide whether to swap variants via prefers-color-scheme media queries (auto) or by filtering
upfront (explicit).themes propagates through context, so a nested PlumaProvider can specify only colorScheme
and resolve against an ancestor's themes:
When a nested PlumaProvider has colorScheme (and themes are in scope, own or inherited), the
matching variant wins over a theme inherited from PlumaThemeContext. To extend the inherited
themes — overriding e.g. only dark — pass a partial themes object: it's merged over the
inherited one, so the unaltered variants stay accessible.
If you're planning to use the Icon component, you'll need to pass in an
IconManager instance. The IconManager class comes from the
@customerio/pluma-icons package.
An IconManager is responsible for importing the icon SVG sprite sheet, and attaching it to the
document body. When PlumaProvider receives an IconManager,
PlumaProvider will instruct IconManager to load and attach the sprites when the app
first renders.
The sprites only get loaded and attached when PlumaProvider renders, so it's safe to instantiate
the IconManager instance outside of components or effects. Additionally, a single
IconManager instance will only attach sprites once, even if called multiple times.
In microfrontends, only the root app needs to provide an IconManager. The sprites are attached to
the document body, and are then available globally, to all embedded microfrontends.
Similar to the theme object, it is recommended to pass in the IconManager instance from the root
app's context into the microfrontend PlumaProvider, in case any components need to reference the
IconManager.
Pluma includes link components such as PlainLink and
Link, which may perform navigation events. By default, those
components render plain a tags, which would use the browser's native navigation,
which cause a full page reload.
In a single page application, there is typically a routing library which takes over linking and issues navigation events internally, without refreshing the whole page. While Pluma itself is agnostic towards what an app's routing setup is, it allows customizing the link component, so that consuming apps may still navigate correctly.
A custom component can be defined on PlumaProvider through the linkComponent prop.
There are a few basic requirements the component must adhere to in order to work correctly:
LinkComponent type
import type { LinkComponent } from '@customerio/pluma-components/react';import type { PlumaLinkComponent, PlumaLinkComponentSignature } from '@customerio/pluma-components/ember';forwardRefhref - a string, the target URL for the router navigationreplace - a boolean, which indicates that the transition should
replaceState rather than pushStatea tag, and not a Box
component, as Pluma already wraps the component in Boxes internallyIn React with React Router, this setup might look like:
In Ember, it might look like:
Note: In Ember apps, we typically use the LinkTo component for router links.
That component accepts arguments like @model and @route instead of a @href
string, which is different from what we require for Pluma's link component.
Our recommendation is to use an addon like ember-link
or a custom helper to generate the href string. Invoking a PlumaLink component
might then look like:
While the helper might be:
Certain components may expose a set of default or configuration props that can be
set from the PlumaProvider level. For example, the Snackbar component's
close timeout can be modified like this.
PlumaProvider accepts a componentConfig prop, which is an object with component names for keys.
Please refer to the individual component docs for more information on what configuration is available.
These flags may be used by specific components to alter their behavior. Certain components can behave or render differently based on these flags. These are all the currently available flags:
unsafe_useLegacyButtonunsafe_useLegacyTextFieldunsafe_useLegacyTextAreaunsafe_useLegacySelectunsafe_useLegacyLinkWhich color scheme to apply.
'light' (default): apply the light tokens.'dark': apply the dark tokens.'auto': detect the user's system preference via
@media (prefers-color-scheme: dark) and apply light or dark tokens
accordingly. The Provider listens for changes and updates dynamically.Ignored when theme is provided — theme always wins.
Any component-focused feature flags to apply
An instance of a GlobalThemeManager, which manages global theme state and variables
By default, global variables will live in a <style> element just under
the PlumaProvider.
If a different container is specified, the the <style> element will be
portaled into that container instead.
An instance of an IconManager, which attaches the icon sprites
Whether the ScrollbarProvider should be disabled, preventing it from measuring scrollbar widths.
The component that will be used for Link and PlainLink
Where to portal components like Tooltip into
Whether an "isolation: isolate" CSS class should be applied to the theme container
Whether the provider should override global variables if provided theme version is newer than the current global theme version.
Whether the theme container div (with theme class name) should be rendered
The theme to apply to the provider
The root element to set theme attributes on. Can be a CSS selector string, an HTMLElement, or a function returning an HTMLElement. Defaults to document.documentElement.
Whether to load baseline styles, which include global styles for the body element.
Whether to load global reset styles (box-sizing, font inheritance, etc.).
Whether the theme variables should be set globally on :root instead
of as a class name on a div container.