@grafana/theme-providers
v0.1.2
Published
React context providers for @grafana/design (color mode, theme, portal)
Readme
@grafana/theme-providers
React context providers for @grafana/design. Houses every Provider/hook pair that the wider @grafana/* design system depends on — color mode, theme name, and portal root — in a single, intentionally small package so that consuming applications only have to deduplicate one thing to keep React context working correctly.
Why this package exists
React context is identity-based: a useContext(MyContext) call only matches a <MyContext.Provider> that originated from the same module instance. If a consuming application accidentally resolves two copies of a package that exports the Provider, the hook in one half of the tree will not see updates from the Provider in the other half — and the failure is silent.
This is especially likely with a fast-iterating monorepo: every minor version bump of @grafana/components would otherwise create the risk of duplicate copies whenever consumers pin slightly different ranges. By keeping the long-lived, identity-sensitive providers in their own package on a slow-moving version cadence, consumers only have to dedupe @grafana/theme-providers once and can iterate on @grafana/components freely.
Install
pnpm add @grafana/theme-providers @grafana/design-tokensThis package has peer dependencies on react, react-dom, @grafana/data, and @grafana/runtime. The data and runtime peers only matter if you use the change-handler components (ColorModeChangeHandler, ThemeNameChangeHandler, or the ColorMode all-in-one wrapper), which subscribe to Grafana's ThemeChangedEvent.
Install exactly one copy
Run pnpm dedupe (or your package manager's equivalent) to ensure node_modules resolves to a single copy of this package. Two resolved copies will silently split the React context tree and break useColorMode, useThemeId, and usePortal for any consumer that reaches across them.
What's in here
| Export | Purpose |
| ------------------------ | ------------------------------------------------------------------------------------------------------- |
| ColorModeProvider | React context for the active 'light' \| 'dark' color mode. Writes data-color-mode on <html>. |
| useColorMode | { colorMode, setColorMode } hook — reads the nearest ColorModeProvider. |
| ThemeNameProvider | React context for the active named theme (experimental). Writes data-theme-name on <html>. |
| useThemeId | { themeId, setThemeId } hook — reads the nearest ThemeNameProvider. |
| PortalProvider | React context for a shared portal root used by Popover, Tooltip, and other floating UI. |
| usePortal | Returns the active portal root (or document.body if allowOutsideProvider: true). |
| ColorModeChangeHandler | Subscribes to ThemeChangedEvent on the app-events bus and keeps ColorModeProvider in sync. |
| ThemeNameChangeHandler | Same, for ThemeNameProvider. |
| ColorMode | All-in-one wrapper: nests ColorModeProvider → ThemeNameProvider → both change handlers in one shot. |
| useColorModeChange | Lower-level hook backing ColorModeChangeHandler — exposed for advanced/manual integrations. |
| useThemeNameChange | Same, for ThemeNameChangeHandler. |
Usage
For a typical Grafana plugin, the ColorMode wrapper is what you want:
import { ColorMode } from '@grafana/theme-providers';
import { getAppEvents, useTheme2 } from '@grafana/runtime';
<ColorMode getAppEvents={getAppEvents} useTheme2={useTheme2}>
<App />
</ColorMode>;For standalone apps (e.g. a custom Storybook host, or a non-Grafana surface that just needs the color-mode toggle), drop the change handlers and use ColorModeProvider directly:
import { ColorModeProvider, useColorMode } from '@grafana/theme-providers';
<ColorModeProvider defaultColorMode="dark">
<App />
</ColorModeProvider>;For floating UI, wrap your app once in PortalProvider so @grafana/components' Popover/Tooltip render against a stable root:
import { PortalProvider } from '@grafana/theme-providers';
<PortalProvider defaultRoot="grafana-portal-container">
<App />
</PortalProvider>;Relationship to other packages
@grafana/design-tokens— supplies theThemeColorMode,LegacyThemeName, etc. types these providers operate on, and the CSS variables thatdata-color-mode/data-theme-nameswitch between.@grafana/components— depends on@grafana/theme-providersand consumesusePortalinternally. Component consumers should not import providers from@grafana/components— that re-export was removed when this package was split out.
License
Apache-2.0
