Skip to content

Design tokens ​

@myghf/ui ships its design tokens as CSS custom properties named --myghf-*. They live in tokens.css and are imported once, from an app entry stylesheet:

css
@import '@myghf/ui/tokens.css';

Every token is a space-separated RGB channel triple (R G B) — not a hex string, and not a complete rgb() value:

css
:root {
  --myghf-primary-500: 0 162 221;   /* channels, not a hex string */
  --myghf-background: 248 249 250;
}

The preset wraps each token with Tailwind's <alpha-value> placeholder, so the channels can be composed with an alpha and the opacity modifiers work:

css
color: rgb(var(--myghf-primary-500));             /* use the channels directly */
background-color: rgb(var(--myghf-primary-500) / 0.5);  /* …or with an alpha */
html
<!-- Tailwind substitutes <alpha-value>, so /50 works -->
<div class="bg-primary-500/50 text-foreground">50% brand blue</div>

See the Tailwind preset reference for the utility mapping.

Live swatches ​

Every token below, rendered from the stylesheet. Toggle the site's appearance to see the semantic layer (and any brand tint) respond.

Primary — MYGHF Blue

Secondary — MYGHF Plum

Success — MYGHF Teal

Warning — MYGHF Gold

Error — MYGHF Red

Info (semantic copy of primary)

Semantic tokens

--myghf-background

--myghf-foreground

--myghf-surface

--myghf-surface-muted

--myghf-border

--myghf-muted

vue
<script setup lang="ts">
// Live swatches read the tokens at runtime, so they follow dark mode with the rest
// of the site. Nothing here is a hard-coded colour — every value resolves through
// `--myghf-*` (`rgb(var(--myghf-*))`).
const scales = [
  { name: 'primary', label: 'Primary — MYGHF Blue' },
  { name: 'secondary', label: 'Secondary — MYGHF Plum' },
  { name: 'success', label: 'Success — MYGHF Teal' },
  { name: 'warning', label: 'Warning — MYGHF Gold' },
  { name: 'error', label: 'Error — MYGHF Red' },
  { name: 'info', label: 'Info (semantic copy of primary)' },
]

const steps = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900]

const semantic = [
  'background',
  'foreground',
  'surface',
  'surface-muted',
  'border',
  'muted',
]

const token = (name: string) => `rgb(var(--myghf-${name}))`
</script>

<template>
  <div class="space-y-5">
    <div v-for="scale in scales" :key="scale.name">
      <p class="mb-1 text-xs font-medium text-muted">{{ scale.label }}</p>
      <div class="flex overflow-hidden rounded-md border border-border" aria-hidden="true">
        <div
          v-for="step in steps"
          :key="step"
          class="h-10 flex-1"
          :style="{ backgroundColor: token(`${scale.name}-${step}`) }"
          :title="`--myghf-${scale.name}-${step}`"
        />
      </div>
    </div>

    <div>
      <p class="mb-1 text-xs font-medium text-muted">Semantic tokens</p>
      <div class="grid grid-cols-2 gap-2 sm:grid-cols-3">
        <div
          v-for="name in semantic"
          :key="name"
          class="overflow-hidden rounded-md border border-border"
        >
          <div class="h-8" :style="{ backgroundColor: token(name) }" aria-hidden="true" />
          <p class="px-2 py-1 text-xs font-medium text-foreground">--myghf-{{ name }}</p>
        </div>
      </div>
    </div>
  </div>
</template>

Semantic tokens ​

The semantic layer describes roles rather than hues, so components styled with bg-surface, text-foreground, and border-border adapt to dark mode with no extra classes. These are the only tokens re-declared by the dark block (see Dark mode).

TokenLight (:root)DarkRole
--myghf-background248 249 25015 18 23App/page background
--myghf-foreground0 0 0243 244 246Body text and default icon colour
--myghf-surface255 255 25526 30 37Cards, panels, popovers
--myghf-surface-muted243 244 24639 44 53Recessed surfaces, hovers
--myghf-border230 230 23055 61 71Dividers and borders
--myghf-muted128 128 128156 163 175Secondary text, placeholders

Brand scales ​

Each brand scale runs 50–900, with 500 as the brand value. These values are the same in light and dark: the dark block does not re-declare these tokens, so a consumer override keeps applying in dark mode.

Primary — MYGHF Blue (500) ​

StepTokenValue
50--myghf-primary-50240 249 253
100--myghf-primary-100217 241 250
200--myghf-primary-200173 225 244
300--myghf-primary-300115 204 236
400--myghf-primary-40056 182 228
500--myghf-primary-5000 162 221
600--myghf-primary-6000 130 177
700--myghf-primary-7000 100 137
800--myghf-primary-8000 73 99
900--myghf-primary-9000 49 66

Secondary — MYGHF Plum (500) ​

StepTokenValue
50--myghf-secondary-50249 244 247
100--myghf-secondary-100240 228 235
200--myghf-secondary-200222 198 213
300--myghf-secondary-300198 157 183
400--myghf-secondary-400175 115 153
500--myghf-secondary-500152 76 124
600--myghf-secondary-600122 61 99
700--myghf-secondary-70094 47 77
800--myghf-secondary-80068 34 56
900--myghf-secondary-90046 23 37

Success — MYGHF Teal (500) ​

StepTokenValue
50--myghf-success-50243 251 250
100--myghf-success-100231 246 245
200--myghf-success-200202 236 234
300--myghf-success-300158 220 216
400--myghf-success-40090 195 189
500--myghf-success-50013 167 158
600--myghf-success-60011 147 139
700--myghf-success-7009 120 114
800--myghf-success-8007 94 88
900--myghf-success-9005 70 66

Warning — MYGHF Gold (500) ​

StepTokenValue
50--myghf-warning-50254 250 242
100--myghf-warning-100252 242 223
200--myghf-warning-200249 227 186
300--myghf-warning-300245 207 136
400--myghf-warning-400241 187 87
500--myghf-warning-500237 168 39
600--myghf-warning-600190 134 31
700--myghf-warning-700147 104 24
800--myghf-warning-800107 76 18
900--myghf-warning-90071 50 12

Error — MYGHF Red (500) ​

StepTokenValue
50--myghf-error-50254 245 244
100--myghf-error-100253 235 234
200--myghf-error-200250 210 208
300--myghf-error-300246 173 170
400--myghf-error-400240 116 111
500--myghf-error-500233 50 43
600--myghf-error-600205 44 38
700--myghf-error-700168 36 31
800--myghf-error-800130 28 24
900--myghf-error-90098 21 18

Info — semantic copy of primary ​

info carries the same channel values as primary. It is a separate scale so feedback styling never couples to the brand scale.

StepTokenValue
50--myghf-info-50240 249 253
100--myghf-info-100217 241 250
200--myghf-info-200173 225 244
300--myghf-info-300115 204 236
400--myghf-info-40056 182 228
500--myghf-info-5000 162 221
600--myghf-info-6000 130 177
700--myghf-info-7000 100 137
800--myghf-info-8000 73 99
900--myghf-info-9000 49 66

Dark mode ​

The dark block sits under two selectors at once, and sets color-scheme: dark so native controls and scrollbars follow:

css
[data-theme='dark'],
.dark {
  color-scheme: dark;

  --myghf-background: 15 18 23;
  --myghf-foreground: 243 244 246;
  --myghf-surface: 26 30 37;
  --myghf-surface-muted: 39 44 53;
  --myghf-border: 55 61 71;
  --myghf-muted: 156 163 175;
}

Three rules matter:

  1. Only the semantic layer is remapped. The brand scales (primary … info, steps 50–900) are not re-declared in the dark block. A consumer's :root override of a brand token therefore keeps applying while dark mode is active — it is never shadowed by a more specific dark rule.
  2. Brand tints need explicit dark: variants. A light tint such as bg-primary-100 is paired with dark:bg-primary-900/40 dark:text-primary-200 (and dark:border-primary-700 for outlines). This is codified in toneClasses and used by Tag, Alert/Message, and Toast; see the theming guide.
  3. dark: utilities require the .dark class. Setting data-theme="dark" by hand drives this token block but leaves Tailwind's dark: variants inactive. useTheme() writes both (its default attribute is 'both') so the two always agree.

Overriding tokens ​

Override any --myghf-* variable after importing tokens.css, so your rule wins by source order:

css
@import '@myghf/ui/tokens.css';

:root {
  --myghf-primary-500: 0 130 177;   /* custom brand blue */
  --myghf-background: 255 255 255;  /* strict brand white */
}

Because the dark block re-declares only the six semantic tokens, a :root override of a brand scale survives dark mode. Prefer overriding tokens to patching component class names.

Tokens are not optional. Without tokens.css, every rgb(var(--myghf-*)) resolves to nothing and the palette collapses.

Released under the MIT License.