Skip to content

@vibe-labs/design-themes-default — Developer Reference

Default theme presets for the Vibe Design System. Provides scoped dark/light surface token overrides for elements with data-theme, plus three accent colour schemes and the Instrument Sans typeface.


Installation

ts
import { DefaultThemes, type DefaultTheme } from "@vibe-labs/design-themes-default";
css
/* Pick a theme (includes common + fonts) */
@import "@vibe-labs/design-themes-default/cyan";
@import "@vibe-labs/design-themes-default/purple";
@import "@vibe-labs/design-themes-default/gold";

Each theme CSS file imports common.css (base token overrides) and fonts.css (Instrument Sans) then adds its own accent colour block.


How It Works

This package applies overrides inside @layer vibe.theme, scoped to [data-theme] selectors. Any element with a data-theme attribute gets the scoped token values, overriding the base design system theme tokens only for that subtree.

html
<!-- Entire page -->
<html data-theme="cyan">

<!-- Scoped region -->
<section data-theme="purple" data-mode="light">
  <!-- light-mode purple theme for this section only -->
</section>

Because these rules live inside @layer vibe.theme, they sit below unlayered CSS — tenant overrides can still win.


Colour Themes

cyan

css
@import "@vibe-labs/design-themes-default/cyan";
TokenValue
--color-accent#53ddf5
--color-accent-dark#16a9c3
--color-accent-light#97edfd
--color-accent-hover#97edfd
--color-accent-active#16a9c3
--color-accent-contrast#000
--color-secondary#7e30ed
--color-secondary-dark#5411ab
--color-secondary-light#ba88ff
--overlay-tintrgba(83, 221, 245, 0.08)

purple / gold

Follow the same pattern with their own accent values. Import ./purple or ./gold.


Common Token Overrides (common.css)

Applied to all elements matching [data-theme].

Dark (default)

CategoryTokens
Surfaces--surface-background: #0e0e0e · --surface-base: #161616 · --surface-subtle: #1e1e1e · --surface-elevated: #272727 · --surface-overlay: #313131 · --surface-modal: #383838
Borders--border-subtle: rgba(255,255,255,0.08) · --border-default: rgba(255,255,255,0.14) · --border-strong: rgba(255,255,255,0.22)
Text--text-primary: #f0f0f0 · --text-secondary: #b0b0b0 · --text-muted: #777 · --text-disabled: #4a4a4a · --text-inverse: #0e0e0e
Status--color-success/warning/danger/info*-400 scale
Overlays--overlay-scrim: rgba(0,0,0,0.5) · --overlay-heavy: rgba(0,0,0,0.7)
Interactions--surface-hover-overlay: rgba(255,255,255,0.06) · --surface-active-overlay: rgba(255,255,255,0.1)
Focus--ring-color: var(--color-accent) · --ring-offset-color: var(--surface-base)
Status surfaces--surface-{success/warning/danger/info}-subtle (10% opacity rgba)

Light ([data-theme][data-mode="light"])

Surfaces invert to neutral light scale. Text flips to neutral-900 scale. Status colours shift to *-500. Overlay opacities drop. Status surfaces use 8% opacity.


Fonts

Instrument Sans loaded via fonts.css (included automatically when importing a theme):

  • InstrumentSans-Latin.woff2 + InstrumentSans-LatinExt.woff2
  • InstrumentSans-Italic-Latin.woff2 + InstrumentSans-Italic-LatinExt.woff2

Sets --font-sans to "Instrument Sans", sans-serif within [data-theme].


TypeScript

ts
import { DefaultThemes, type DefaultTheme } from "@vibe-labs/design-themes-default";

DefaultThemes // ["purple", "cyan", "gold"] as const
type DefaultTheme  // "purple" | "cyan" | "gold"

Use for type-safe theme switching in Vue or plain JS:

ts
function setTheme(el: HTMLElement, theme: DefaultTheme) {
  el.dataset.theme = theme;
}

Dist Structure

FileDescription
common.cssBase dark/light token overrides for [data-theme]
fonts.cssInstrument Sans @font-face declarations
cyan.cssCyan accent theme (imports common + fonts)
purple.cssPurple accent theme
gold.cssGold accent theme
index.js / index.d.tsTypeScript constants and types

Dependencies

Requires @vibe-labs/design for base token definitions. The [data-theme] overrides reference --color-neutral-* and --color-{status}-{stop} from the design package.


Build

bash
npm run build

Build: rimraf dist && ncp src dist && tsc --rootDir types --outDir dist


Adding a New Theme

  1. Create src/{name}.css that imports ./common.css and ./fonts.css, then adds a [data-theme="{name}"] block with --color-accent and related tokens
  2. Add "types/index.ts" — extend DefaultThemes array with the new name
  3. Add the export to package.json
  4. Run npm run build

Usage Guide

Scoped accent colour themes with dark/light mode support. Apply a data-theme attribute to any element to activate a theme for that subtree.

Import

css
/* Pick one (each includes common + fonts) */
@import "@vibe-labs/design-themes-default/cyan";
@import "@vibe-labs/design-themes-default/purple";
@import "@vibe-labs/design-themes-default/gold";
ts
import { DefaultThemes, type DefaultTheme } from "@vibe-labs/design-themes-default";

Apply a Theme

html
<!-- Full page: cyan dark (default) -->
<html data-theme="cyan">

<!-- Full page: purple light -->
<html data-theme="purple" data-mode="light">

<!-- Scoped: a panel with its own theme -->
<aside data-theme="gold">...</aside>

<!-- System mode within a theme -->
<html data-theme="cyan" data-mode="system">

Theme Switching (Vue)

vue
<script setup lang="ts">
import { ref } from "vue";
import { DefaultThemes, type DefaultTheme } from "@vibe-labs/design-themes-default";

const theme = ref<DefaultTheme>("cyan");

function setTheme(t: DefaultTheme) {
  theme.value = t;
  document.documentElement.dataset.theme = t;
}
</script>

<template>
  <div class="flex gap-2">
    <button
      v-for="t in DefaultThemes"
      :key="t"
      :data-variant="theme === t ? 'primary' : 'secondary'"
      class="btn"
      @click="setTheme(t)"
    >
      {{ t }}
    </button>
  </div>
</template>

Overriding Accent Tokens

After loading a theme, override accent tokens with unlayered CSS (wins over @layer vibe.theme):

css
/* Custom tenant colour, not in the default themes */
:root {
  --color-accent: #ff6b35;
  --color-accent-dark: #cc4f1f;
  --color-accent-light: #ff9a73;
  --color-accent-hover: #ff9a73;
  --color-accent-active: #cc4f1f;
  --color-accent-contrast: #fff;
}

Nested Theme Regions

html
<!-- Main interface in cyan -->
<div data-theme="cyan">
  <nav class="bg-base">Main nav</nav>

  <!-- Promotional sidebar in gold -->
  <aside data-theme="gold" class="bg-base p-6">
    <h2 class="text-primary">Upgrade</h2>
  </aside>
</div>

Light Mode with a Theme

html
<html data-theme="purple" data-mode="light">
  <!-- Surfaces flip to light neutral scale, accent stays purple -->
</html>

Type-Safe Theme Prop (Vue Component)

vue
<script setup lang="ts">
import type { DefaultTheme } from "@vibe-labs/design-themes-default";

const props = defineProps<{
  theme?: DefaultTheme;
}>();
</script>

<template>
  <div :data-theme="theme">
    <slot />
  </div>
</template>

Vibe