Overview
Blueprint 6 styles its components from CSS custom properties in the --bp-* namespace (verified in 6.21): intent colors, a palette, surface values, typography colors, and focus-ring settings, all defined on :root in blueprint.css. Override those tokens to retheme. Class names keep the bp6- prefix. Package setup is in blueprint.
Override --bp-* tokens, not component CSS
Set tokens on :root (or a scope) after Blueprint’s stylesheet loads. Intent colors come in five states, so override all five together.
:root {
--bp-intent-primary-rest: #1f5fbf;
--bp-intent-primary-hover: #194d9c;
--bp-intent-primary-active: #143d7d;
--bp-intent-primary-disabled: #6f9be0;
--bp-intent-primary-foreground: #ffffff;
}Provide the full intent set (default, primary, success, warning, danger) whenever you change one, so intents stay distinct. Other groups: --bp-palette-*, --bp-surface-* (borders, shadows, background colors, --bp-surface-border-radius, --bp-surface-spacing), --bp-typography-color-*, and --bp-emphasis-focus-*. Inspect :root in DevTools for the current list, since new tokens appear in minor releases.
Check contrast: --bp-intent-primary-foreground on --bp-intent-primary-rest needs 4.5:1 for button text. If the brand color fails, darken the token and keep the bright brand color for decoration.
Treat compiled Sass overrides as ineffective
$pt-* Sass variables (such as $pt-grid-size) exist in @blueprintjs/core/lib/scss/variables.scss for your own Sass. Setting them before importing the compiled blueprint.css changes nothing, because that CSS is already compiled, and colors come from the --bp-* tokens. Verify any Sass-based override in the rendered output.
Toggle dark mode on a high ancestor
Dark mode applies when .bp6-dark or data-bp-color-scheme="dark" is on an ancestor. Put it on <html> so portal-rendered overlays, which mount on document.body, are covered too.
useEffect(() => {
document.documentElement.classList.toggle("bp6-dark", dark);
}, [dark]);Read the stored preference (and prefers-color-scheme as the fallback) before first render to avoid a flash. For a themed custom container, add the class on that element; see blueprint-overlays for the portal rules.
Override dark surface tokens inside the dark scope
The dark scope redefines only surface (borders, shadows, default background) and default typography tokens. Where .bp6-dark sits below :root on a wrapper element, its own definitions beat an inherited :root override, so repeat the override under the dark selector. Intent colors are shared by both modes.
.bp6-dark {
--bp-surface-background-color-default-rest: #0b0f14;
}Do not patch compiled CSS or depend on internals
Editing node_modules/.../blueprint.css breaks on every install. For a one-off adjustment, scope a rule to your own wrapper class, for example .my-compact-table .bp6-table-cell { padding: 2px 6px; }. Blueprint does not guarantee class names across minor versions, so prefer tokens for anything systemic.
Keep visible focus for keyboard users
FocusStyleManager.onlyShowFocusOnTabs() hides focus rings after a mouse click and restores them for keyboard navigation. Call it once at startup, and skip it for apps with heavy keyboard or screen-reader use. Tune the ring itself with --bp-emphasis-focus-color, -width, and -offset. See accessibility.