or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

binding-animation.mdcore-diagram.mddata-models.mdgeometry-collections.mdgraphobject-hierarchy.mdindex.mdinteractive-tools.mdlayout-system.mdtheme-management.mdvisual-elements.md
tile.json

theme-management.mddocs/

Theme Management

GoJS v3.0+ introduces comprehensive theme management capabilities that allow for dynamic switching between light, dark, and custom themes. The theme system provides centralized control over colors, fonts, and other visual properties across all diagram elements.

Capabilities

ThemeManager

The ThemeManager coordinates theme switching and maintains theme data for one or more diagrams.

class ThemeManager {
  /**
   * Creates a new ThemeManager with default light and dark themes.
   * @param init - Optional initialization properties
   */
  constructor(init?: Partial<ThemeManager>);
  
  // Theme Collections
  themeMap: Map<string, Theme>;
  
  // Active Theme Configuration
  currentTheme: string;              // Current active theme name ('light', 'dark', 'system', or custom)
  defaultTheme: string;              // Fallback theme name (default: 'light')
  preferredColorScheme: 'light' | 'dark';  // Browser's preferred color scheme (read-only)
  
  // Integration Options
  changesDivBackground: boolean;     // Whether to update diagram div background color
  
  // Diagram Management
  addDiagram(diagram: Diagram): this;
  removeDiagram(diagram: Diagram): this;
  
  // Theme Operations
  set(themeName: string, props: Partial<Theme>): this;
  findValue(prop: string | string[] | number, source?: string | string[], tprop?: string): any;
  getValue(theme: Theme, prop: string | string[] | number, source?: string | string[], tprop?: string): any;
  findTheme(themeName: string): Theme | undefined;
}

Usage Examples:

// Basic theme setup with automatic div background
const themeManager = new go.ThemeManager({
  currentTheme: 'system',          // Follow browser preference
  changesDivBackground: true       // Update div background color
});

// Add diagram to theme management
themeManager.addDiagram(myDiagram);
myDiagram.themeManager = themeManager;

// Switch themes programmatically
themeManager.currentTheme = 'dark';

// Custom theme creation
themeManager.set('custom', {
  colors: {
    text: '#333333',
    group: '#e3f2fd',
    selection: '#1976d2'
  }
});

// Apply custom theme
themeManager.currentTheme = 'custom';

Themes (Built-in Definitions)

Static class providing default light and dark theme definitions.

class Themes {
  static readonly Light: Theme;     // Default light theme
  static readonly Dark: Theme;      // Default dark theme
}

Theme Interface

Defines the structure for theme objects containing colors, fonts, and other visual properties.

interface Theme {
  colors?: ThemeColors;             // Color palette
  fonts?: ThemeValues<string>;      // Font definitions
  numbers?: ThemeValues<number>;    // Numeric values (stroke widths, etc.)
  points?: ThemeValues<Point>;      // Point coordinates
  sizes?: ThemeValues<Size>;        // Size definitions
  rects?: ThemeValues<Rect>;        // Rectangle definitions
  margins?: ThemeValues<Margin>;    // Margin definitions
  spots?: ThemeValues<Spot>;        // Spot definitions
  arrowheads?: ThemeValues<string>; // Arrowhead styles
  targetPropertyMap?: Map<string, string>;  // Property mapping overrides
  [index: string]: ThemeValues<any> | undefined;  // Custom properties
}

interface ThemeColors {
  text?: BrushLike;           // Text color for nodes and labels
  comment?: BrushLike;        // Comment/annotation color
  link?: BrushLike;           // Link stroke/fill color
  group?: BrushLike;          // Group background color
  outline?: BrushLike;        // Group border color
  selection?: BrushLike;      // Selection highlight color
  div?: string;               // Diagram div background color
  gridMinor?: BrushLike;      // Minor grid line color
  gridMajor?: BrushLike;      // Major grid line color
  overviewBox?: BrushLike;    // Overview viewport box color
  tempLink?: BrushLike;       // Temporary link color during linking
  tempPort?: BrushLike;       // Temporary port highlight color
  adornmentFill?: BrushLike;  // Tool handle fill color
  adornmentStroke?: BrushLike; // Tool handle border color
  dragSelect?: BrushLike;     // Drag selection box color
  [index: string]: BrushLike | BrushLike[] | ThemeColors | undefined;
}

interface ThemeValues<T> {
  [index: string]: T;
}

ThemeBinding

Specialized binding class that automatically updates properties based on theme changes.

class ThemeBinding extends Binding {
  /**
   * Creates a new ThemeBinding.
   * @param targetprop - Target property name on the GraphObject
   * @param sourceprop - Source property path in the theme
   * @param themeSource - Source object within theme (e.g., 'colors', 'fonts')
   * @param conv - Converter function for the target property
   * @param themeConverter - Converter function for the theme value
   */
  constructor(
    targetprop?: string,
    sourceprop?: string, 
    themeSource?: string,
    conv?: TargetConversion,
    themeConverter?: TargetConversion
  );
  
  themeSource: string | null;           // Theme source object path
  themeConverter: TargetConversion;     // Theme value converter function
  
  ofData(): this;                       // Configure for data object source
}

Default Themes

Light Theme

{
  colors: {
    text: '#0a0a0a',          // Neutral 950 - dark text
    comment: '#ca8a04',       // Yellow 600 - amber comments
    link: '#0a0a0a',          // Neutral 950 - dark links
    group: '#a3a3a344',       // Neutral 400 - light gray groups (transparent)
    outline: '#a3a3a3',       // Neutral 400 - gray outlines
    selection: '#0ea5e9',     // Sky 500 - blue selection
    div: '#fff',              // White background
    gridMinor: '#e5e5e5',     // Neutral 200 - light grid
    gridMajor: '#a3a3a3',     // Neutral 400 - darker grid
    overviewBox: '#c026d3',   // Fuschia 600 - magenta overview
    tempLink: '#2563eb',      // Blue 600 - blue temporary links
    tempPort: '#c026d3',      // Fuschia 600 - magenta ports
    adornmentFill: '#0ea5e9', // Sky 500 - blue handles
    adornmentStroke: '#1e40af', // Blue 800 - dark blue borders
    dragSelect: '#c026d3'     // Fuschia 600 - magenta selection box
  },
  fonts: {
    normal: '10pt sans-serif',
    bold: 'bold 12pt sans-serif'
  },
  numbers: {
    group: 1,                 // Group stroke width
    selection: 3              // Selection stroke width
  },
  margins: {
    group: new go.Margin(5)   // Group padding
  },
  arrowheads: {
    toArrow: 'Standard'
  }
}

Dark Theme

{
  colors: {
    text: '#f5f5f5',          // Neutral 100 - light text
    comment: '#facc15',       // Yellow 400 - bright amber comments
    link: '#f5f5f5',          // Neutral 100 - light links
    group: '#a3a3a388',       // Neutral 400 - gray groups (more transparent)
    outline: '#a3a3a3',       // Neutral 400 - gray outlines
    selection: '#38bdf8',     // Sky 400 - lighter blue selection
    div: '#171717',           // Neutral 900 - dark background
    gridMinor: '#262626',     // Neutral 800 - dark grid
    gridMajor: '#404040',     // Neutral 700 - lighter grid
    overviewBox: '#e879f9',   // Fuschia 400 - lighter magenta overview
    tempLink: '#60a5fa',      // Blue 400 - lighter blue temporary links
    tempPort: '#e879f9',      // Fuschia 400 - lighter magenta ports
    adornmentFill: '#38bdf8', // Sky 400 - lighter blue handles
    adornmentStroke: '#2563eb', // Blue 600 - blue borders
    dragSelect: '#e879f9'     // Fuschia 400 - lighter magenta selection box
  },
  fonts: {
    normal: '10pt sans-serif',
    bold: 'bold 12pt sans-serif'
  },
  numbers: {
    group: 1,                 // Group stroke width
    selection: 3              // Selection stroke width
  },
  margins: {
    group: new go.Margin(5)   // Group padding
  },
  arrowheads: {
    toArrow: 'Standard'
  }
}

Theme Bindings

Theme bindings automatically update GraphObject properties when themes change.

Binding Methods

All GraphObjects provide convenience methods for creating theme bindings:

// Standard theme binding
theme(targetprop: string, sourceprop?: string, themeSource?: string, conv?: TargetConversion, themeconv?: TargetConversion): this;

// Theme binding to data object
themeData(targetprop: string, sourceprop?: string, themeSource?: string, conv?: TargetConversion, themeconv?: TargetConversion): this;

// Theme binding to named object
themeObject(targetprop: string, sourceprop?: string, objectSrcname?: string, themeSource?: string, conv?: TargetConversion, themeconv?: TargetConversion): this;

// Theme binding to model
themeModel(targetprop: string, sourceprop?: string, themeSource?: string, conv?: TargetConversion, themeconv?: TargetConversion): this;

Usage Examples

// Theme-aware node template
myDiagram.nodeTemplate = 
  new go.Node('Auto')
    .add(
      new go.Shape('RoundedRectangle', {
        fill: 'white',
        strokeWidth: 1
      })
        .theme('fill', 'group', 'colors')      // Use theme's group color
        .theme('stroke', 'outline', 'colors'), // Use theme's outline color
      new go.TextBlock({ 
        margin: 8,
        font: '12pt sans-serif'
      })
        .theme('stroke', 'text', 'colors')     // Use theme's text color
        .theme('font', 'normal', 'fonts')      // Use theme's normal font
        .bind('text', 'name')
    );

// Theme-aware link template
myDiagram.linkTemplate =
  new go.Link({ routing: go.Routing.Orthogonal })
    .add(
      new go.Shape({ strokeWidth: 2 })
        .theme('stroke', 'link', 'colors'),    // Use theme's link color
      new go.Shape({ toArrow: 'Standard' })
        .theme('stroke', 'link', 'colors')     // Use theme's link color
        .theme('toArrow', 'toArrow', 'arrowheads') // Use theme's arrow style
    );

// Complex theme binding with converter
new go.Shape()
  .theme('fill', 'selection', 'colors', null, (color) => {
    return go.Brush.lighten(color, 0.3); // Lighten selection color by 30%
  });

Advanced Usage

Custom Themes

// Create a custom business theme
themeManager.set('business', {
  colors: {
    text: '#2c3e50',
    group: '#ecf0f1',
    outline: '#34495e',
    selection: '#3498db',
    link: '#34495e',
    div: '#ffffff'
  },
  fonts: {
    normal: '11pt "Segoe UI", Arial, sans-serif',
    bold: 'bold 13pt "Segoe UI", Arial, sans-serif'
  },
  numbers: {
    group: 2,
    selection: 4
  }
});

// High contrast theme for accessibility
themeManager.set('high-contrast', {
  colors: {
    text: '#000000',
    group: '#ffffff',
    outline: '#000000',
    selection: '#ffff00',
    link: '#000000',
    div: '#ffffff'
  },
  numbers: {
    group: 3,
    selection: 5
  }
});

System Integration

// Automatic theme switching based on system preference
const themeManager = new go.ThemeManager({
  currentTheme: 'system',
  changesDivBackground: true
});

// Listen for system theme changes
if (window.matchMedia) {
  const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
  mediaQuery.addListener(() => {
    // ThemeManager automatically handles system preference changes
    myDiagram.updateAllThemeBindings();
  });
}

// Manual theme switching UI
function switchTheme(themeName) {
  themeManager.currentTheme = themeName;
  // All theme bindings update automatically
}

Theme Property Validation

// Validate theme completeness
function validateTheme(theme) {
  const requiredColors = ['text', 'group', 'outline', 'selection', 'link'];
  const missing = requiredColors.filter(color => !theme.colors?.[color]);
  
  if (missing.length > 0) {
    console.warn('Theme missing required colors:', missing);
  }
  
  return missing.length === 0;
}

// Apply theme with validation
if (validateTheme(myCustomTheme)) {
  themeManager.set('custom', myCustomTheme);
  themeManager.currentTheme = 'custom';
}

The GoJS v3.0+ theme system provides powerful, centralized control over diagram appearance with seamless switching between predefined and custom themes, automatic system integration, and comprehensive binding capabilities.