Skip to main content
To create a custom theme, define your own set of CSS variables that override the base theme variables and declarative colors for both light and dark modes.
Namespace your theme using the bq-theme attribute (e.g., bq-theme="my-custom-theme") or a matching CSS class (e.g., .my-custom-theme).

Step-by-step guide

1

Define base theme variables

Create a CSS file for your custom theme (e.g., custom-theme.css) and set the base design tokens:
[bq-theme="my-custom-theme"],
.my-custom-theme {
  /* Override font family */
  --bq-font-family: 'Inter', sans-serif;

  /* Define brand colors using any primitive color from the palette */
  --bq-brand-light: var(--bq-blue-100);
  --bq-brand:       var(--bq-blue-600);
  --bq-brand-dark:  var(--bq-blue-1000);

  /* Define accent colors */
  --bq-accent-light: var(--bq-purple-100);
  --bq-accent:       var(--bq-purple-600);
  --bq-accent-dark:  var(--bq-purple-1000);

  /* Override neutral scale if needed */
  --bq-neutral-50:  var(--bq-grey-50);
  --bq-neutral-100: var(--bq-grey-100);
  /* ... continue with other neutrals ... */

  /* Define semantic colors */
  --bq-success: var(--bq-teal-600);
  --bq-danger:  var(--bq-red-600);
  --bq-warning: var(--bq-gold-600);
  --bq-info:    var(--bq-blue-600);
  --bq-focus:   var(--bq-blue-600);

  /* Interactive state overlays */
  --bq-state--hover:  rgba(0, 0, 0, 0.08);  /* Subtle hover overlay (light mode) */
  --bq-state--active: rgba(0, 0, 0, 0.12); /* Pressed state overlay (light mode) */
}
Override --bq-state--hover and --bq-state--active for each mode. In dark mode, use light overlays (e.g. rgba(255, 255, 255, 0.1)) instead of dark ones.
2

Define light mode theme

Define the declarative color tokens for the light mode:
[bq-theme="my-custom-theme"]:not([bq-mode]),    /* Default — no mode specified */
[bq-theme="my-custom-theme"][bq-mode="light"],  /* Explicit light mode (via attributes) */
.my-custom-theme:not([bq-mode]),                /* Default — no mode (via CSS class) */
.my-custom-theme.light {                        /* Explicit light mode (via CSS classes) */

  /* Background colors */
  --bq-background--primary:   var(--bq-white);
  --bq-background--secondary: var(--bq-neutral-100);
  --bq-background--tertiary:  var(--bq-neutral-200);
  --bq-background--alt:       var(--bq-neutral-300);
  --bq-background--inverse:   var(--bq-neutral-900);
  --bq-background--brand:     var(--bq-brand);
  --bq-background--overlay:   var(--bq-neutral-900);

  /* Icon colors */
  --bq-icon--primary:   var(--bq-neutral-800);
  --bq-icon--secondary: var(--bq-neutral-600);
  --bq-icon--inverse:   var(--bq-neutral-50);
  --bq-icon--brand:     var(--bq-brand);
  --bq-icon--alt:       var(--bq-white);
  --bq-icon--info:      var(--bq-info);
  --bq-icon--success:   var(--bq-success);
  --bq-icon--warning:   var(--bq-warning);
  --bq-icon--danger:    var(--bq-danger);

  /* Stroke colors */
  --bq-stroke--primary:   var(--bq-neutral-200);
  --bq-stroke--secondary: var(--bq-neutral-600);
  --bq-stroke--tertiary:  var(--bq-neutral-900);
  --bq-stroke--inverse:   var(--bq-white);
  --bq-stroke--brand:     var(--bq-brand);
  --bq-stroke--alt:       var(--bq-neutral-50);
  --bq-stroke--success:   var(--bq-success);
  --bq-stroke--warning:   var(--bq-warning);
  --bq-stroke--danger:    var(--bq-danger);

  /* Text colors */
  --bq-text--primary:   var(--bq-neutral-800);
  --bq-text--secondary: var(--bq-neutral-600);
  --bq-text--inverse:   var(--bq-neutral-50);
  --bq-text--brand:     var(--bq-brand);
  --bq-text--alt:       var(--bq-white);
  --bq-text--info:      var(--bq-info);
  --bq-text--success:   var(--bq-success);
  --bq-text--warning:   var(--bq-warning);
  --bq-text--danger:    var(--bq-danger);

  /* UI colors */
  --bq-ui--primary:      var(--bq-white);
  --bq-ui--secondary:    var(--bq-neutral-100);
  --bq-ui--tertiary:     var(--bq-neutral-500);
  --bq-ui--inverse:      var(--bq-neutral-900);
  --bq-ui--brand:        var(--bq-brand);
  --bq-ui--brand-alt:    var(--bq-brand-light);
  --bq-ui--alt:          var(--bq-neutral-50);
  --bq-ui--success:      var(--bq-success);
  --bq-ui--success-alt:  var(--bq-success-light);
  --bq-ui--warning:      var(--bq-warning);
  --bq-ui--warning-alt:  var(--bq-warning-light);
  --bq-ui--danger:       var(--bq-danger);
  --bq-ui--danger-alt:   var(--bq-danger-light);
}
3

Define dark mode theme

Define the declarative color tokens for the dark mode:
[bq-theme="my-custom-theme"][bq-mode="dark"],  /* Explicit dark mode (via attributes) */
.my-custom-theme.dark {                        /* Explicit dark mode (via CSS classes) */

  /* Background colors */
  --bq-background--primary:   var(--bq-neutral-1000);
  --bq-background--secondary: var(--bq-neutral-950);
  --bq-background--tertiary:  var(--bq-neutral-800);
  --bq-background--alt:       var(--bq-neutral-700);
  --bq-background--inverse:   var(--bq-neutral-600);
  --bq-background--brand:     var(--bq-brand);
  --bq-background--overlay:   var(--bq-neutral-900);

  /* Icon colors */
  --bq-icon--primary:   var(--bq-neutral-100);
  --bq-icon--secondary: var(--bq-neutral-400);
  --bq-icon--inverse:   var(--bq-neutral-800);
  --bq-icon--brand:     var(--bq-brand);
  --bq-icon--alt:       var(--bq-white);
  --bq-icon--info:      var(--bq-info);
  --bq-icon--success:   var(--bq-success);
  --bq-icon--warning:   var(--bq-warning);
  --bq-icon--danger:    var(--bq-danger);

  /* Stroke colors */
  --bq-stroke--primary:   var(--bq-neutral-900);
  --bq-stroke--secondary: var(--bq-neutral-700);
  --bq-stroke--tertiary:  var(--bq-neutral-400);
  --bq-stroke--inverse:   var(--bq-neutral-950);
  --bq-stroke--brand:     var(--bq-brand);
  --bq-stroke--alt:       var(--bq-neutral-1000);
  --bq-stroke--success:   var(--bq-success);
  --bq-stroke--warning:   var(--bq-warning);
  --bq-stroke--danger:    var(--bq-danger);

  /* Text colors */
  --bq-text--primary:   var(--bq-neutral-100);
  --bq-text--secondary: var(--bq-neutral-400);
  --bq-text--inverse:   var(--bq-neutral-800);
  --bq-text--brand:     var(--bq-brand);
  --bq-text--alt:       var(--bq-white);
  --bq-text--info:      var(--bq-info);
  --bq-text--success:   var(--bq-success);
  --bq-text--warning:   var(--bq-warning);
  --bq-text--danger:    var(--bq-danger);

  /* UI colors */
  --bq-ui--primary:      var(--bq-neutral-900);
  --bq-ui--secondary:    var(--bq-neutral-950);
  --bq-ui--tertiary:     var(--bq-neutral-700);
  --bq-ui--inverse:      var(--bq-neutral-100);
  --bq-ui--brand:        var(--bq-brand);
  --bq-ui--brand-alt:    var(--bq-brand-dark);
  --bq-ui--alt:          var(--bq-neutral-950);
  --bq-ui--success:      var(--bq-success);
  --bq-ui--success-alt:  var(--bq-success-dark);
  --bq-ui--warning:      var(--bq-warning);
  --bq-ui--warning-alt:  var(--bq-warning-dark);
  --bq-ui--danger:       var(--bq-danger);
  --bq-ui--danger-alt:   var(--bq-danger-dark);
}
4

Apply your custom theme

Include your custom theme CSS file in your project and set the bq-theme and bq-mode attributes on the <html> element:
Always load beeq.css before your custom theme CSS so that your variables correctly override the defaults.
<!DOCTYPE html>
<html lang="en" bq-theme="my-custom-theme" bq-mode="light">
  <head>
    <link rel="stylesheet" href="path/to/beeq.css">
    <link rel="stylesheet" href="path/to/custom-theme.css">
  </head>
  <body>
    <!-- Your components will automatically use the custom theme -->
    <bq-button>Click me</bq-button>
  </body>
</html>
To switch to dark mode, change the bq-mode attribute:
<html lang="en" bq-theme="my-custom-theme" bq-mode="dark">
You can also use CSS classes instead of HTML attributes:
<body class="my-custom-theme light"> ... </body>
<!-- or -->
<body class="my-custom-theme dark"> ... </body>

Full example: TechFlow theme

Here is an almost production-ready custom theme called TechFlow — a theme with vibrant teal accents and a sleek design aesthetic.