Skip to content

Theme

CSS Variables

Theming is heavily centered around the :root selector and CSS variables.

Common

css
:root {
  --font-family: 'Open Sans', sans-serif;
  --font-size: 14px;
  --font-size-sm: 14px;
  --font-size-md: 14px;
  --font-size-lg: 14px;
  --font-size-xl: 14px;
  --font-weight: normal;

  /* keep 'spacing' an even value */
  --spacing: 6px;

  --form-element-active-border-color: var(--primary);
  --form-element-spacing-vertical: calc(var(--spacing) / 2);
  --form-element-spacing-horizontal: var(--spacing);
  --form-element-background-color: var(--bg-1);
  --form-element-disabled-background-color: var(--bg-0);
  --form-element-disabled-border-color: #415462;
  --form-element-disabled-opacity: 0.3;

  --switch-color: var(--primary-inverse);
  --switch-checked-background-color: var(--primary);

  --nav-link-spacing-vertical: calc(var(--spacing) / 2);
  --nav-link-spacing-horizontal: var(--spacing);
  --nav-element-spacing-vertical: calc(var(--spacing) / 2);
  --nav-element-spacing-horizontal: var(--spacing);

  --card-background-color: var(--bg-0);
  --card-sectionning-background-color: var(--bg-1);

  --code-color: var(--primary);
  --code-background-color: var(--bg-1);

  --table-border-color: rgba(var(--text-2), 0.2);

  --block-spacing-vertical: var(--spacing);
  --block-spacing-horizontal: var(--spacing);

  --accordion-border-color: rgba(var(--text-2), 0.2);
  --accordion-open-summary-color: var(--primary);

  --dropdown-background-color: var(--bg-1);
  --dropdown-hover-background-color: var(--bg-0);

  --modal-overlay-background-color: rgba(var(--base-2), 0.35);

  --grid-spacing-vertical: var(--spacing);

  --typography-spacing-vertical: 25px;
}
:root {
  --font-family: 'Open Sans', sans-serif;
  --font-size: 14px;
  --font-size-sm: 14px;
  --font-size-md: 14px;
  --font-size-lg: 14px;
  --font-size-xl: 14px;
  --font-weight: normal;

  /* keep 'spacing' an even value */
  --spacing: 6px;

  --form-element-active-border-color: var(--primary);
  --form-element-spacing-vertical: calc(var(--spacing) / 2);
  --form-element-spacing-horizontal: var(--spacing);
  --form-element-background-color: var(--bg-1);
  --form-element-disabled-background-color: var(--bg-0);
  --form-element-disabled-border-color: #415462;
  --form-element-disabled-opacity: 0.3;

  --switch-color: var(--primary-inverse);
  --switch-checked-background-color: var(--primary);

  --nav-link-spacing-vertical: calc(var(--spacing) / 2);
  --nav-link-spacing-horizontal: var(--spacing);
  --nav-element-spacing-vertical: calc(var(--spacing) / 2);
  --nav-element-spacing-horizontal: var(--spacing);

  --card-background-color: var(--bg-0);
  --card-sectionning-background-color: var(--bg-1);

  --code-color: var(--primary);
  --code-background-color: var(--bg-1);

  --table-border-color: rgba(var(--text-2), 0.2);

  --block-spacing-vertical: var(--spacing);
  --block-spacing-horizontal: var(--spacing);

  --accordion-border-color: rgba(var(--text-2), 0.2);
  --accordion-open-summary-color: var(--primary);

  --dropdown-background-color: var(--bg-1);
  --dropdown-hover-background-color: var(--bg-0);

  --modal-overlay-background-color: rgba(var(--base-2), 0.35);

  --grid-spacing-vertical: var(--spacing);

  --typography-spacing-vertical: 25px;
}

Dark

css
/* Dark colors (default) */
:root,
:root:not([data-theme]),
:root:not([data-theme='light']) {
  color-scheme: dark;

  --primary: rgb(var(--accent-0));
  --primary-hover: rgb(148, 224, 17);
  --primary-focus: rgba(205, 249, 127, 0.2);
  --primary-inverse: rgb(var(--text-inverse));

  --secondary: #5684f1;
  --secondary-hover: #3b6ee4;
  --secondary-focus: rgba(205, 249, 127, 0.2);
  --secondary-inverse: #fff;

  --bg-0: #101010;
  --bg-1: #181818;
  --bg-2: #252525;

  --color: #eaeaea;
  --background-color: var(--bg-2);

  --text-0: 255, 255, 255;
  --text-1: 215, 215, 215;
  --text-2: 156, 160, 164;
  --text-inverse: 0, 0, 0;

  --base-0: 20, 20, 20;
  --base-1: 40, 40, 40;
  --base-2: 61, 61, 61;

  --accent-0: 192, 248, 95;
  --accent-1: 198, 249, 111;
  --accent-2: 205, 249, 127;

  --neutral-0: 119, 119, 122;
  --neutral-1: 116, 124, 133;
  --neutral-2: 132, 138, 147;

  --color-0: #c0f85f;
  --color-1: #cb9cf8;
  --color-2: #779ef7;
  --color-3: #37c43e;
  --color-4: #5737c4;
  --color-5: #8c1fab;
  --color-6: #4fc0e8;
  --color-7: #f7458e;
  --color-8: #fe7e6d;
  --color-9: #ffe35b;
  --color-10: #fc7db7;
  --color-11: #2237c4;
  --color-12: #3b254c;

  --color-error: #f74318;

  --border-radius: 4px;
  --shadow: 0px 1px 1px 0px rgb(var(--base-1));
}
/* Dark colors (default) */
:root,
:root:not([data-theme]),
:root:not([data-theme='light']) {
  color-scheme: dark;

  --primary: rgb(var(--accent-0));
  --primary-hover: rgb(148, 224, 17);
  --primary-focus: rgba(205, 249, 127, 0.2);
  --primary-inverse: rgb(var(--text-inverse));

  --secondary: #5684f1;
  --secondary-hover: #3b6ee4;
  --secondary-focus: rgba(205, 249, 127, 0.2);
  --secondary-inverse: #fff;

  --bg-0: #101010;
  --bg-1: #181818;
  --bg-2: #252525;

  --color: #eaeaea;
  --background-color: var(--bg-2);

  --text-0: 255, 255, 255;
  --text-1: 215, 215, 215;
  --text-2: 156, 160, 164;
  --text-inverse: 0, 0, 0;

  --base-0: 20, 20, 20;
  --base-1: 40, 40, 40;
  --base-2: 61, 61, 61;

  --accent-0: 192, 248, 95;
  --accent-1: 198, 249, 111;
  --accent-2: 205, 249, 127;

  --neutral-0: 119, 119, 122;
  --neutral-1: 116, 124, 133;
  --neutral-2: 132, 138, 147;

  --color-0: #c0f85f;
  --color-1: #cb9cf8;
  --color-2: #779ef7;
  --color-3: #37c43e;
  --color-4: #5737c4;
  --color-5: #8c1fab;
  --color-6: #4fc0e8;
  --color-7: #f7458e;
  --color-8: #fe7e6d;
  --color-9: #ffe35b;
  --color-10: #fc7db7;
  --color-11: #2237c4;
  --color-12: #3b254c;

  --color-error: #f74318;

  --border-radius: 4px;
  --shadow: 0px 1px 1px 0px rgb(var(--base-1));
}

Light

css
/* Light colors */
:root[data-theme='light'] {
  color-scheme: light;

  --primary: #37c43e;
  --primary-hover: #4fd24a;
  --primary-focus: rgba(205, 249, 127, 0.6);
  --primary-inverse: rgb(var(--text-inverse));

  --secondary: #5684f1;
  --secondary-hover: #3b6ee4;
  --secondary-focus: rgba(205, 249, 127, 0.2);
  --secondary-inverse: #fff;

  --bg-0: #efefef;
  --bg-1: #fafafa;
  --bg-2: #fff;

  --color: #151515;
  --background-color: var(--bg-2);

  --text-0: 0, 0, 0;
  --text-1: 20, 20, 20;
  --text-2: 40, 40, 40;
  --text-inverse: 255, 255, 255;

  --base-0: 255, 255, 255;
  --base-1: 240, 240, 240;
  --base-2: 224, 226, 228;

  --accent-0: 55, 196, 62;
  --accent-1: 178, 246, 58;
  --accent-2: 192, 248, 95;

  --neutral-0: 119, 119, 122;
  --neutral-1: 116, 124, 133;
  --neutral-2: 132, 138, 147;

  --color-0: #a2e163;
  --color-5: #d55ef7;
  --color-7: #d74186;
  --color-8: #fe7d3e;
  --color-9: #ffc645;
  --color-10: #ea70bf;
}
/* Light colors */
:root[data-theme='light'] {
  color-scheme: light;

  --primary: #37c43e;
  --primary-hover: #4fd24a;
  --primary-focus: rgba(205, 249, 127, 0.6);
  --primary-inverse: rgb(var(--text-inverse));

  --secondary: #5684f1;
  --secondary-hover: #3b6ee4;
  --secondary-focus: rgba(205, 249, 127, 0.2);
  --secondary-inverse: #fff;

  --bg-0: #efefef;
  --bg-1: #fafafa;
  --bg-2: #fff;

  --color: #151515;
  --background-color: var(--bg-2);

  --text-0: 0, 0, 0;
  --text-1: 20, 20, 20;
  --text-2: 40, 40, 40;
  --text-inverse: 255, 255, 255;

  --base-0: 255, 255, 255;
  --base-1: 240, 240, 240;
  --base-2: 224, 226, 228;

  --accent-0: 55, 196, 62;
  --accent-1: 178, 246, 58;
  --accent-2: 192, 248, 95;

  --neutral-0: 119, 119, 122;
  --neutral-1: 116, 124, 133;
  --neutral-2: 132, 138, 147;

  --color-0: #a2e163;
  --color-5: #d55ef7;
  --color-7: #d74186;
  --color-8: #fe7d3e;
  --color-9: #ffc645;
  --color-10: #ea70bf;
}

Toggle theme

Changing between 'light' and 'dark' theme is a matter of updating html[data-theme]:

js
document.documentElement.setAttribute('data-theme', 'light');
document.documentElement.setAttribute('data-theme', 'light');

Local storage

An example of persistent storage of the theme choice to the localStorage:

js
function loadTheme(defaultTheme = 'dark', key = 'app.theme') {
  let theme = localStorage.getItem(key);
  if (!theme) {
    // if theme is not stored in local storage, load from `<html />`
    // and fallback to `defaultTheme` if none
    theme = document.documentElement.getAttribute('data-theme')
      ?? defaultTheme;
    // store theme to local storage
    localStorage.setItem(key, theme);
  }
  // update `<html />` theme
  document.documentElement.setAttribute('data-theme', theme);
}
function loadTheme(defaultTheme = 'dark', key = 'app.theme') {
  let theme = localStorage.getItem(key);
  if (!theme) {
    // if theme is not stored in local storage, load from `<html />`
    // and fallback to `defaultTheme` if none
    theme = document.documentElement.getAttribute('data-theme')
      ?? defaultTheme;
    // store theme to local storage
    localStorage.setItem(key, theme);
  }
  // update `<html />` theme
  document.documentElement.setAttribute('data-theme', theme);
}