Color modes
Color modes are token-level. The provider sets data-bs-theme on its
wrapper; a [data-bs-theme=‘dark’] block overrides the surface tokens,
and every component follows because it reads those tokens.
The mechanism
The library defines its tokens twice:
- On the root, the light values (
--bs-body-bg,--bs-body-color,--bs-border-color, the per-color emphasis tokens, …). - Inside a
[data-bs-theme='dark']block, the dark overrides for those same tokens.
BootstrapStyledProvider renders a wrapper with data-bs-theme={colorMode}. When the
mode is dark, that attribute activates the dark block for the wrapper and everything
inside it. Because the switch is a scoped attribute selector — not a global change —
nesting a second provider re-scopes a subtree independently.
<BootstrapStyledProvider colorMode="dark">
{/* everything here reads the dark tokens */}
</BootstrapStyledProvider> Side by side
Two providers, same markup, different colorMode — the surface, text, borders, and
controls differ only in their tokens:
What flips
The mode changes the neutral surface and emphasis tokens; the eight contextual colors stay the same hue (their emphasis tints adjust for contrast):
| Token | Changes with the mode |
|---|---|
| —bs-body-bg · —bs-body-color | Page background and text. |
| —bs-secondary-bg · —bs-tertiary-bg | The raised / sunken surface layers. |
| —bs-border-color | Default border color. |
| —bs-emphasis-color | High-contrast text. |
| —bs-{color}-text-emphasis | Per-color emphasis text, re-tuned for the dark surface. |
| —bs-link-color | Link color, adjusted for contrast. |
Customizing the dark palette
The dark token values live under theme.dark and can be overridden with
createTheme, just like the light tokens:
import { createTheme } from '@metatoy/bootstrap-styled';
const theme = createTheme({
dark: {
body: { bg: '#0d0e0c', color: '#ece9f1' },
},
}); Portaled overlays
Overlays (Modal, Dropdown, Tooltip, Popover, Offcanvas) render through a portal into
document.body, outside the provider wrapper. The library re-establishes the
data-bs-theme scope on the portal root from the active mode, so overlays match — no
extra work. For the app-level toggle pattern and the useColorMode hook, see
Dark mode.