Skip to content

Theming

The GlyphJS theming system uses CSS custom properties (variables) prefixed with --glyph- to style all components. Two built-in themes (light and dark) ship with @glyphjs/runtime, and you can create fully custom themes by providing your own variable map.

Two-tier theme model

GlyphJS uses a two-tier approach — the same model used by Obsidian, Radix UI, and shadcn/ui:

Tier 1 — 53 semantic tokens (required by TypeScript). These are the building blocks: colors, accent, spacing, radius, effects, semantic states, and a shared color palette. Set these in your theme object and every component gets correct colors automatically.

Tier 2 — Component-specific overrides (optional, CSS-only). Individual component variables like --glyph-kanban-card-bg or --glyph-steps-active-color are valid CSS custom properties that cascade from Tier 1 tokens. They are not enforced by TypeScript. Advanced users can override them with plain CSS when needed.

/* Optional Tier 2 override — no TypeScript required */
[data-glyph-theme="corporate"] {
--glyph-kanban-card-bg: #f0f4ff;
--glyph-steps-active-color: #0066cc;
}

GlyphTheme interface

interface GlyphTheme {
name: string;
variables: Record<string, string>; // CSS variable name → value
}
FieldTypeDescription
namestringIdentifier for the theme (e.g. light, dark, corporate). Set as data-glyph-theme on the wrapper.
variablesRecord<string, string>Map of CSS variable names to values. All keys should start with --glyph-.

ThemeProvider & RuntimeProvider

Both providers accept a theme prop (string shortcut or full GlyphTheme object) and render a wrapper <div> with all --glyph-* CSS variables applied as inline styles.

import { ThemeProvider } from '@glyphjs/runtime';
<ThemeProvider theme="dark">
{/* components inherit dark theme variables */}
</ThemeProvider>

className prop

Apply a CSS class to the theme wrapper <div>. Useful for adding animations, pseudo-elements, or scoping CSS.

<ThemeProvider theme="dark" className="my-glyph-wrapper">
{children}
</ThemeProvider>

style prop

Merge additional inline styles with the theme variables. Consumer styles take precedence over theme values, enabling targeted overrides.

<ThemeProvider
theme="dark"
style={{ maxWidth: 960, margin: '0 auto' }}
>
{children}
</ThemeProvider>

The same className and style props are available on RuntimeProvider:

<RuntimeProvider
registry={registry}
references={refs}
theme={myTheme}
className="glyph-app"
style={{ padding: '2rem' }}
>
{children}
</RuntimeProvider>

Tier 1 variables

All 53 Tier 1 variables are required when defining a custom theme. They are enforced by the GlyphThemeVars TypeScript type.

Core colors

VariableLightDarkDescription
--glyph-bgtransparent#0a0e1aBackground color
--glyph-text#1a2035#d4dae3Primary text color
--glyph-text-muted#6b7a94#6b7a94Secondary/muted text
--glyph-heading#0a0e1a#edf0f5Heading text color
--glyph-link#0a9d7c#00d4aaLink color
--glyph-link-hover#088a6c#33e0beLink hover color
--glyph-border#d0d8e4#1a2035Border color
--glyph-border-strong#a8b5c8#2a3550Strong border
--glyph-surface#e8ecf3#0f1526Surface background
--glyph-surface-raised#f4f6fa#162038Raised surface

Accent

VariableLightDarkDescription
--glyph-accent#0a9d7c#00d4aaPrimary accent color
--glyph-accent-hover#088a6c#33e0beAccent hover state
--glyph-accent-subtle#e6f6f2#0a1a1aSubtle accent background
--glyph-accent-muted#b0ddd0#1a4a3aMuted accent color
--glyph-text-on-accent#fff#0a0e1aText on accent backgrounds

Code

VariableLightDark
--glyph-code-bg#e8ecf3#0f1526
--glyph-code-text#1a2035#d4dae3

Typography

VariableValue
--glyph-font-body"Inter", "Helvetica Neue", system-ui, sans-serif
--glyph-font-heading"Inter", "Helvetica Neue", system-ui, sans-serif
--glyph-font-monoui-monospace, "Cascadia Code", "Fira Code", monospace

Spacing

VariableValue
--glyph-spacing-xs0.25rem
--glyph-spacing-sm0.5rem
--glyph-spacing-md1rem
--glyph-spacing-lg1.5rem
--glyph-spacing-xl2rem

Border radius

VariableValue
--glyph-radius-xs0.25rem
--glyph-radius-sm0.375rem
--glyph-radius-md0.5rem
--glyph-radius-lg0.75rem

Effects

VariableLightDarkDescription
--glyph-shadow-sm0 1px 3px rgba(0,0,0,0.1)0 1px 3px rgba(0,0,0,0.4)Subtle shadow
--glyph-shadow-md0 4px 12px rgba(0,0,0,0.15)0 4px 12px rgba(0,0,0,0.5)Medium shadow
--glyph-shadow-lg0 8px 30px rgba(0,0,0,0.2)0 8px 30px rgba(0,0,0,0.6)Large shadow
--glyph-transition0.2s ease0.2s easeDefault transition timing
--glyph-focus-ring0 0 0 2px #0a9d7c0 0 0 2px #00d4aaFocus ring box-shadow
--glyph-opacity-muted0.70.7Muted element opacity
--glyph-opacity-disabled0.40.4Disabled element opacity

Semantic states

Four universal state colors used by components across the system (Steps, KPI, Comparison, Kanban priority, Quiz, Callouts, Form validation, and more).

VariableLightDarkDescription
--glyph-color-success#16a34a#4ade80Success / positive
--glyph-color-warning#d97706#fbbf24Warning / caution
--glyph-color-error#dc2626#f87171Error / negative
--glyph-color-info#38bdf8#38bdf8Info / neutral

Shared palette

Ten slots used for charts, timelines, infographics, and other multi-series visualizations.

VariableLightDark
--glyph-palette-color-1#00d4aa#00d4aa
--glyph-palette-color-2#b44dff#b44dff
--glyph-palette-color-3#22c55e#4ade80
--glyph-palette-color-4#e040fb#e040fb
--glyph-palette-color-5#00e5ff#00e5ff
--glyph-palette-color-6#84cc16#bef264
--glyph-palette-color-7#f472b6#f472b6
--glyph-palette-color-8#fb923c#fb923c
--glyph-palette-color-9#818cf8#818cf8
--glyph-palette-color-10#38bdf8#38bdf8

Misc

VariableLightDarkDescription
--glyph-tooltip-bgrgba(10,14,26,0.9)rgba(0,0,0,0.9)Tooltip background
--glyph-tooltip-text#f4f6fa#d4dae3Tooltip text color
--glyph-rating-star-fill#f59e0b#fbbf24Rating star fill color

useGlyphTheme hook

The useGlyphTheme() React hook returns a GlyphThemeContext:

interface GlyphThemeContext {
name: string;
resolveVar: (varName: string) => string;
isDark: boolean;
}

Use inside a ThemeProvider or RuntimeProvider:

import { useGlyphTheme } from '@glyphjs/runtime';
function MyComponent() {
const theme = useGlyphTheme();
const bg = theme.resolveVar('--glyph-bg');
return <div style={{ background: bg }} />;
}

Throws if called outside a theme context.


Theme resolution + dark detection

The resolveTheme function normalizes theme input:

import { resolveTheme } from '@glyphjs/runtime';
const theme = resolveTheme('light'); // returns lightTheme
const theme = resolveTheme('dark'); // returns darkTheme
const theme = resolveTheme(undefined); // defaults to lightTheme
const theme = resolveTheme(customTheme); // returns as-is

isDarkTheme(theme) heuristically determines if a theme is dark by inspecting the --glyph-bg variable luminance, falling back to checking if name contains "dark".


Component-level overrides

Plugins ship themeDefaults on their definition. These merge with lower priority than theme values. mergeThemeDefaults(theme, defaults) combines them: theme values win over plugin defaults.


Runtime theme switching

Change the theme at runtime via runtime.setTheme():

runtime.setTheme('dark');
runtime.setTheme(myCustomTheme);

CSS selector overrides

The theme wrapper renders data-glyph-theme="<name>" on its <div>. You can use this for advanced CSS targeting:

/* Override accent for a specific theme */
[data-glyph-theme="corporate"] {
--glyph-accent: #0066cc;
}
/* Tier 2 override — component-specific, CSS only */
[data-glyph-theme="corporate"] {
--glyph-kanban-priority-high: #c62828;
--glyph-steps-active-color: #0066cc;
}
/* Add a scanline effect on dark themes */
[data-glyph-theme="dark"]::after {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background: repeating-linear-gradient(
transparent 0px,
rgba(0, 0, 0, 0.03) 2px,
transparent 4px
);
}

Combined with the className prop, you can scope animations and pseudo-element effects:

<ThemeProvider theme={myTheme} className="animated-glyph">
{children}
</ThemeProvider>
.animated-glyph .glyph-graph-node rect {
transition: var(--glyph-transition);
}
.animated-glyph .glyph-graph-node:hover rect {
filter: brightness(1.2);
}

Example: Cyberpunk 2077 theme

This showcase theme demonstrates all 53 Tier 1 variables. It uses deep chrome-black backgrounds, neon yellow accents (the signature Cyberpunk 2077 color #fcee09), cyber-red and electric blue semantic states, and an aggressive neon palette.

import type { GlyphTheme } from '@glyphjs/types';
export const cyberpunk2077Theme: GlyphTheme = {
name: 'cyberpunk-2077',
variables: {
// Core colors — deep chrome-black with electric white-blue text
'--glyph-bg': '#0d0d0d',
'--glyph-text': '#e0f7fa',
'--glyph-text-muted': '#7b8fa3',
'--glyph-heading': '#fcee09',
'--glyph-link': '#00f0ff',
'--glyph-link-hover': '#ff003c',
'--glyph-border': 'rgba(252,238,9,0.3)',
'--glyph-border-strong': 'rgba(252,238,9,0.5)',
'--glyph-surface': '#1a1a2e',
'--glyph-surface-raised': '#1f1020',
// Accent — hot neon yellow
'--glyph-accent': '#fcee09',
'--glyph-accent-hover': '#ffe566',
'--glyph-accent-subtle': '#1a1a08',
'--glyph-accent-muted': '#3d3a0e',
'--glyph-text-on-accent': '#0d0d0d',
// Code
'--glyph-code-bg': '#1a1a2e',
'--glyph-code-text': '#00f0ff',
// Typography — cyberpunk-style fonts
'--glyph-font-body': '"Rajdhani", "Share Tech", system-ui, sans-serif',
'--glyph-font-heading': '"Orbitron", "Audiowide", system-ui, sans-serif',
'--glyph-font-mono': '"Fira Code", "JetBrains Mono", ui-monospace, monospace',
// Spacing
'--glyph-spacing-xs': '0.25rem',
'--glyph-spacing-sm': '0.5rem',
'--glyph-spacing-md': '1rem',
'--glyph-spacing-lg': '1.5rem',
'--glyph-spacing-xl': '2rem',
// Border radius — sharp, angular
'--glyph-radius-xs': '1px',
'--glyph-radius-sm': '2px',
'--glyph-radius-md': '4px',
'--glyph-radius-lg': '6px',
// Effects — aggressive neon glow
'--glyph-shadow-sm': '0 1px 4px rgba(252,238,9,0.15)',
'--glyph-shadow-md': '0 4px 16px rgba(252,238,9,0.2)',
'--glyph-shadow-lg': '0 0 20px rgba(252,238,9,0.4), 0 0 60px rgba(252,238,9,0.1)',
'--glyph-transition': '0.15s ease-out',
'--glyph-focus-ring': '0 0 0 2px #fcee09, 0 0 12px rgba(252,238,9,0.5)',
'--glyph-opacity-muted': '0.65',
'--glyph-opacity-disabled': '0.35',
// Semantic states — cyber neons
'--glyph-color-success': '#39ff14',
'--glyph-color-warning': '#fcee09',
'--glyph-color-error': '#ff003c',
'--glyph-color-info': '#00f0ff',
// Shared palette — neon spectrum
'--glyph-palette-color-1': '#fcee09',
'--glyph-palette-color-2': '#00f0ff',
'--glyph-palette-color-3': '#39ff14',
'--glyph-palette-color-4': '#ff003c',
'--glyph-palette-color-5': '#ff6ec7',
'--glyph-palette-color-6': '#7df9ff',
'--glyph-palette-color-7': '#bf5fff',
'--glyph-palette-color-8': '#fb923c',
'--glyph-palette-color-9': '#c8fb50',
'--glyph-palette-color-10': '#f5a0c5',
// Misc
'--glyph-tooltip-bg': 'rgba(13,13,13,0.95)',
'--glyph-tooltip-text': '#fcee09',
'--glyph-rating-star-fill': '#fcee09',
},
};

Using the theme

import { ThemeProvider } from '@glyphjs/runtime';
import { cyberpunk2077Theme } from './cyberpunk-theme';
function App() {
return (
<ThemeProvider
theme={cyberpunk2077Theme}
className="cyberpunk-wrapper"
>
<GlyphDocument ir={ir} />
</ThemeProvider>
);
}

Optional CSS enhancements

Pair the theme with CSS for scanline and glow effects using the data-glyph-theme selector:

/* CRT scanline overlay */
[data-glyph-theme="cyberpunk-2077"]::after {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background: repeating-linear-gradient(
transparent 0px,
rgba(0, 0, 0, 0.05) 2px,
transparent 4px
);
z-index: 999;
}
/* Glow on hovered graph nodes */
.cyberpunk-wrapper .glyph-graph-node:hover rect,
.cyberpunk-wrapper .glyph-architecture-node:hover rect {
filter: brightness(1.3) drop-shadow(0 0 8px rgba(252, 238, 9, 0.6));
transition: var(--glyph-transition);
}

Cyberpunk 2077 theme in action

The examples below render live components using the Cyberpunk 2077 theme defined above. They showcase how the palette, semantic state, and accent variables affect complex components.

Graph — Microservices dependency map

A directed acyclic graph of a microservices architecture. Notice the neon palette on node fills and the accent-colored focus indicators.

Architecture — Cloud infrastructure

A nested cloud infrastructure diagram with VPC zones, public and private subnets, and service dependencies.

Chart — System metrics over time

A multi-series line chart tracking system metrics. The palette colors (--glyph-palette-color-1..10) drive the series colors.