Skip to the contentSkip to the navigation
RootsGitHubMenu

Theming

A Roots app has twelve colour tokens. roots.lisp sets them, the base styles, the UI kit and the colour utilities (bg-primary, text-muted, border-error) use them, and each is a CSS variable (--roots-primary) for your own styles.

:theme (:primary "#8a5200" :accent "#2c6a47" :bg "#f7f4ea" :surface "#efeadb" :text "#141c1a"
        :dark (:primary "#f0a640" :accent "#93c3a0" :bg "#0f1716" :surface "#15201e" :text "#ebe6d8"))

Those are the colours of this site. The build measures them: a text colour that is under 4.5:1 on its background is the warning B168, with the ratio.

Light and dark #

Dark mode follows the system until the app chooses. The choice is made with the theme API of roots/platform, remembered on the device, and applied before the first paint on the next visit.

The theme switchstatic previewdemos/theme-switch.vue
You chose system; the page shows light.
theme-switch.vue
<script setup lang="ts">
import { theme } from "roots/platform"

const choices = ["system", "light", "dark"] as const
</script>

<template>
  <Box class="theme-switch gap-3">
    <Box class="flex-row gap-2" role="group" aria-label="Theme">
      <Button v-for="choice in choices" :key="choice" :label="choice" :aria-pressed="theme.current.value === choice"
              :class="{ 'theme-switch-on': theme.current.value === choice }" @click="theme.set(choice)" />
    </Box>
    <Box class="theme-switch-swatches flex-row gap-2">
      <span class="theme-switch-swatch bg-primary"></span>
      <span class="theme-switch-swatch bg-accent"></span>
      <span class="theme-switch-swatch bg-surface"></span>
      <span class="theme-switch-swatch bg-text"></span>
    </Box>
    <Text>You chose <strong>{{ theme.current.value }}</strong>; the page shows <strong>{{ theme.resolved.value }}</strong>.</Text>
  </Box>
</template>

<style>
.theme-switch { max-width: 30rem; }
.theme-switch-swatches { flex-wrap: wrap; }
.theme-switch-on { outline: 2px solid var(--roots-primary); outline-offset: 1px; }
.theme-switch-swatch { width: 44px; height: 28px; border-radius: 6px; border: 1px solid var(--roots-border); }
</style>
  • theme.set("dark" | "light" | "system") chooses.
  • theme.current is the choice, theme.resolved what is shown now; both are refs.
  • The switch in this site's header is the same API. In a terminal the same calls switch the terminal app's colour scheme.

The details (the variables besides the tokens, how the stylesheet switches without JavaScript, theme.js) are in Building apps: Theme.