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}| Field | Type | Description |
|---|---|---|
name | string | Identifier for the theme (e.g. light, dark, corporate). Set as data-glyph-theme on the wrapper. |
variables | Record<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
| Variable | Light | Dark | Description |
|---|---|---|---|
--glyph-bg | transparent | #0a0e1a | Background color |
--glyph-text | #1a2035 | #d4dae3 | Primary text color |
--glyph-text-muted | #6b7a94 | #6b7a94 | Secondary/muted text |
--glyph-heading | #0a0e1a | #edf0f5 | Heading text color |
--glyph-link | #0a9d7c | #00d4aa | Link color |
--glyph-link-hover | #088a6c | #33e0be | Link hover color |
--glyph-border | #d0d8e4 | #1a2035 | Border color |
--glyph-border-strong | #a8b5c8 | #2a3550 | Strong border |
--glyph-surface | #e8ecf3 | #0f1526 | Surface background |
--glyph-surface-raised | #f4f6fa | #162038 | Raised surface |
Accent
| Variable | Light | Dark | Description |
|---|---|---|---|
--glyph-accent | #0a9d7c | #00d4aa | Primary accent color |
--glyph-accent-hover | #088a6c | #33e0be | Accent hover state |
--glyph-accent-subtle | #e6f6f2 | #0a1a1a | Subtle accent background |
--glyph-accent-muted | #b0ddd0 | #1a4a3a | Muted accent color |
--glyph-text-on-accent | #fff | #0a0e1a | Text on accent backgrounds |
Code
| Variable | Light | Dark |
|---|---|---|
--glyph-code-bg | #e8ecf3 | #0f1526 |
--glyph-code-text | #1a2035 | #d4dae3 |
Typography
| Variable | Value |
|---|---|
--glyph-font-body | "Inter", "Helvetica Neue", system-ui, sans-serif |
--glyph-font-heading | "Inter", "Helvetica Neue", system-ui, sans-serif |
--glyph-font-mono | ui-monospace, "Cascadia Code", "Fira Code", monospace |
Spacing
| Variable | Value |
|---|---|
--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
| Variable | Value |
|---|---|
--glyph-radius-xs | 0.25rem |
--glyph-radius-sm | 0.375rem |
--glyph-radius-md | 0.5rem |
--glyph-radius-lg | 0.75rem |
Effects
| Variable | Light | Dark | Description |
|---|---|---|---|
--glyph-shadow-sm | 0 1px 3px rgba(0,0,0,0.1) | 0 1px 3px rgba(0,0,0,0.4) | Subtle shadow |
--glyph-shadow-md | 0 4px 12px rgba(0,0,0,0.15) | 0 4px 12px rgba(0,0,0,0.5) | Medium shadow |
--glyph-shadow-lg | 0 8px 30px rgba(0,0,0,0.2) | 0 8px 30px rgba(0,0,0,0.6) | Large shadow |
--glyph-transition | 0.2s ease | 0.2s ease | Default transition timing |
--glyph-focus-ring | 0 0 0 2px #0a9d7c | 0 0 0 2px #00d4aa | Focus ring box-shadow |
--glyph-opacity-muted | 0.7 | 0.7 | Muted element opacity |
--glyph-opacity-disabled | 0.4 | 0.4 | Disabled 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).
| Variable | Light | Dark | Description |
|---|---|---|---|
--glyph-color-success | #16a34a | #4ade80 | Success / positive |
--glyph-color-warning | #d97706 | #fbbf24 | Warning / caution |
--glyph-color-error | #dc2626 | #f87171 | Error / negative |
--glyph-color-info | #38bdf8 | #38bdf8 | Info / neutral |
Shared palette
Ten slots used for charts, timelines, infographics, and other multi-series visualizations.
| Variable | Light | Dark |
|---|---|---|
--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
| Variable | Light | Dark | Description |
|---|---|---|---|
--glyph-tooltip-bg | rgba(10,14,26,0.9) | rgba(0,0,0,0.9) | Tooltip background |
--glyph-tooltip-text | #f4f6fa | #d4dae3 | Tooltip text color |
--glyph-rating-star-fill | #f59e0b | #fbbf24 | Rating 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 lightThemeconst theme = resolveTheme('dark'); // returns darkThemeconst theme = resolveTheme(undefined); // defaults to lightThemeconst theme = resolveTheme(customTheme); // returns as-isisDarkTheme(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.