Color Management
Vuetty includes a color system for defining, resolving, and applying colors in terminal apps. It builds on chalk for terminal string styling.
Color System Overview
Supported Color Formats
Vuetty supports multiple color formats through chalk:
- Named colors: All standard chalk color names (
red,green,blue,yellow,cyan,magenta,white,black,gray,blackBright,redBright,greenBright, etc.) - Hex colors: 3-digit (
#F00) or 6-digit hexadecimal codes (#FF5733,#4a4a4a) - RGB colors: CSS-style RGB notation (
rgb(255, 87, 51)) with values from 0-255
How Colors Work in Vuetty
When you specify a color in Vuetty:
- Color Parsing: The
colorUtils.jsmodule parses your color value using optimized regex patterns - Format Detection: Automatically detects if the color is named, hex, or RGB format
- Chalk Chain Creation: Creates the appropriate chalk color chain based on the format
- Terminal Detection: Chalk detects the terminal's color capabilities
- ANSI Code Generation: Appropriate ANSI escape codes are generated
- Terminal Rendering: The codes are applied to the terminal output
This process keeps output compatible across terminal emulators while staying efficient.
Color Resolution Process
Vuetty uses a deterministic color resolution flow:
For Foreground Colors:
- Check if it's a named color (e.g.,
red,blue) - Check if it's a hex color matching
#RGBor#RRGGBBpattern - Check if it's an RGB color matching
rgb(r, g, b)pattern - Validate RGB values are within 0-255 range
For Background Colors:
- Try named background colors (e.g.,
bgRed,bgBlue) - Use
bgHex()for hex colors - Use
bgRgb()for RGB colors with validation
All invalid colors return null and fall back to defaults.
Color Usage
Apply colors through the theme configuration. Mix formats as needed:
// In your theme configuration
const theme = {
// Named colors - fast and readable
background: 'black',
foreground: 'white',
// Hex colors - precise color control
primary: '#569cd6',
secondary: '#4ec9b0',
// RGB colors - programmatic color generation
success: 'rgb(106, 153, 85)',
components: {
button: {
variants: {
primary: {
bg: '#569cd6', // Hex background
color: 'white' // Named foreground
},
danger: {
bg: 'rgb(244, 71, 71)', // RGB background
color: '#ffffff' // Hex foreground
}
}
}
}
};Theme Color Structure
Global Colors
The theme provides global color settings that apply across your application:
background: Global screen background colorforeground: Default text colorprimary: Primary accent colorsecondary: Secondary accent colorsuccess: Success state color (typically green)warning: Warning state color (typically yellow)danger: Danger/error state color (typically red)info: Informational color (typically cyan or blue)
Component-Specific Colors
Each component can have its own color configuration:
components: {
box: {
color: 'cyan', // Border color
bg: 'black' // Background color
},
textInput: {
color: 'white', // Text color
bg: 'black', // Background color
focusColor: 'magenta', // Focus indicator color
errorColor: 'red' // Error state color
}
}How Colors Work
Chalk Integration
Vuetty uses chalk under the hood for color operations via colorUtils.js. Chalk provides:
- Cross-platform support: Works across different terminal emulators
- Color detection: Automatically detects terminal color support (16, 256, or 16M colors)
- Fallback handling: Gracefully degrades when colors aren't supported
- Performance: Optimized for terminal rendering with pre-compiled regex patterns
Color Resolution Pipeline
When a color is specified in the theme:
- Pre-validation: Check if color value exists and is a string
- Format Detection: Use pre-compiled regex patterns for fast format detection
HEX_COLOR_REGEX: Matches#RGBor#RRGGBBpatternsRGB_COLOR_REGEX: Matchesrgb(r, g, b)patterns (case-insensitive)
- Chalk Chain Creation: Create appropriate chalk method chain:
- Named colors: Direct property access (e.g.,
chalk.red) - Hex colors:
chalk.hex()orchalk.bgHex() - RGB colors:
chalk.rgb()orchalk.bgRgb()with validation
- Named colors: Direct property access (e.g.,
- Terminal Rendering: Chalk generates ANSI escape codes based on terminal capabilities
Performance Optimizations
Vuetty's color system includes several optimizations:
- Pre-compiled Regex: Color patterns are compiled once at module load
- Fast Path for Named Colors: Direct property access without regex
- Lazy Validation: RGB validation only happens after format match
- Cache Normalization:
normalizeColorForCache()ensures consistent cache keys- Hex colors: Converted to lowercase (
#FF5733→#ff5733) - RGB colors: Spaces removed (
rgb(255, 87, 51)→rgb(255,87,51)) - Named colors: Used as-is
- Hex colors: Converted to lowercase (
Color Inheritance
Vuetty's theming system supports color inheritance:
- If a component doesn't specify a color, it falls back to parent component colors
- If no parent color is available, it uses the global
foregroundcolor - If
foregroundis not set, it uses the terminal's default text color
Best Practices
Choosing Color Formats
Use Named Colors When:
- You need standard terminal colors
- Readability is important in your theme file
- You want the fastest color resolution
- Example:
'red','blue','cyan'
Use Hex Colors When:
- You need precise color matching
- You're matching a brand color palette
- You have existing hex values from design systems
- Example:
'#569cd6','#f00'
Use RGB Colors When:
- You're generating colors programmatically
- You need to calculate color values dynamically
- You're working with color manipulation libraries
- Example:
'rgb(106, 153, 85)'
Color Accessibility
Consider terminal accessibility when choosing colors:
- Ensure sufficient contrast between text and background
- Avoid relying solely on color to convey information
- Test your color scheme in different terminal emulators
- Consider users with color vision deficiencies
- Remember: Not all terminals support 16M colors (some only support 256 or 16)
Performance Considerations
- Prefer named colors for the fastest resolution (no regex needed)
- Normalize colors: Use
normalizeColorForCache()for consistent cache keys - Reuse color definitions across components to benefit from caching
- Limit unique colors to reduce memory footprint
- Test with actual terminals to ensure colors display correctly
- Avoid dynamic color generation in hot render paths
Examples
Basic Color Usage (Named Colors)
import { vuetty } from 'vuetty';
import MyComponent from './MyComponent.vue';
const app = vuetty(MyComponent, {
theme: {
background: 'black',
foreground: 'white',
primary: 'cyan',
secondary: 'magenta',
success: 'green',
warning: 'yellow',
danger: 'red',
components: {
button: {
variants: {
primary: { bg: 'blue', color: 'white' },
danger: { bg: 'red', color: 'white' }
}
}
}
}
});Advanced Color Configuration (Mixed Formats)
const theme = {
// Global colors using hex for precision
background: '#1e1e1e',
foreground: '#d4d4d4',
// Semantic colors (mix of hex and named)
primary: '#569cd6',
secondary: '#4ec9b0',
success: '#6a9955',
warning: 'yellow',
danger: '#f44747',
info: '#9cdcfe',
// Component colors with mixed formats
components: {
textInput: {
color: '#d4d4d4',
bg: 'black',
focusColor: 'rgb(86, 156, 214)',
errorColor: '#f44747'
},
box: {
color: '#569cd6',
bg: '#1e1e1e'
},
button: {
variants: {
primary: {
bg: '#569cd6',
color: '#ffffff',
bold: true
},
success: {
bg: 'rgb(106, 153, 85)',
color: 'white',
bold: true
}
}
}
}
};Programmatic Color Generation
// Generate shades programmatically using RGB
function generateShades(baseR, baseG, baseB, count) {
return Array.from({ length: count }, (_, i) => {
const factor = (i + 1) / count;
return `rgb(${Math.round(baseR * factor)}, ${Math.round(baseG * factor)}, ${Math.round(baseB * factor)})`;
});
}
const shades = generateShades(86, 156, 214, 5);
const theme = {
primary: shades[4], // Brightest
primaryDark: shades[2], // Darker
primaryDarker: shades[0], // Darkest
};Short Hex Colors
// Use 3-digit hex for common colors (more concise)
const theme = {
background: '#000', // Black
foreground: '#fff', // White
primary: '#08f', // Bright blue
danger: '#f00', // Pure red
success: '#0f0', // Pure green
};Troubleshooting
Colors Not Displaying
If colors aren't displaying correctly:
- Check terminal color support: Run
echo $COLORTERMor test withchalkdirectly - Verify color format: Ensure your color strings match one of the supported formats
- Named:
'red'(not'Red'or'RED') - Hex:
'#FF5733'or'#f57'(must start with#) - RGB:
'rgb(255, 87, 51)'(must match exact format, spaces optional)
- Named:
- Check for invalid values:
- RGB values must be 0-255
- Hex must be 3 or 6 digits
- Named colors must be valid chalk color names
- Test color resolution: Invalid colors return
nulland fall back to defaults
Color Format Errors
Common mistakes and fixes:
// ❌ Wrong
color: 'RGB(255, 0, 0)' // Uppercase not supported by regex
color: '#12345' // Invalid hex length (must be 3 or 6)
color: 'rgb(300, 0, 0)' // RGB values > 255
color: 'rgb(255,0,0,0.5)' // RGBA not supported
// ✅ Correct
color: 'rgb(255, 0, 0)' // Lowercase, proper format
color: '#123456' // 6-digit hex
color: 'rgb(255, 0, 0)' // Valid range
color: 'red' // Use named color insteadColor Performance Issues
If you experience performance issues with colors:
- Profile color usage: Check if colors are being resolved repeatedly
- Use named colors: Fastest path (no regex matching)
- Normalize for caching: Use
normalizeColorForCache()for cache keys - Reduce unique colors: Fewer unique colors = better caching
- Avoid hot path generation: Don't generate RGB strings in render loops
Debugging Color Resolution
To debug color issues, check the resolution chain:
import { getChalkColorChain, getChalkBgChain } from './utils/colorUtils.js';
// Test foreground color
const fgChain = getChalkColorChain('#569cd6');
console.log(fgChain ? 'Color resolved' : 'Color failed');
// Test background color
const bgChain = getChalkBgChain('rgb(255, 87, 51)');
console.log(bgChain ? 'Background resolved' : 'Background failed');Technical Implementation
Color Utilities Module
Vuetty's color system is implemented in src/utils/colorUtils.js. The module provides three main functions:
getChalkColorChain(color, chalkChain)
Resolves foreground colors and returns a chalk chain:
// Named color - fastest path
getChalkColorChain('red', chalk) // → chalk.red
// Hex color
getChalkColorChain('#569cd6', chalk) // → chalk.hex('#569cd6')
// RGB color
getChalkColorChain('rgb(86, 156, 214)', chalk) // → chalk.rgb(86, 156, 214)
// Invalid color
getChalkColorChain('invalid', chalk) // → nullgetChalkBgChain(bg, chalkChain)
Resolves background colors and returns a chalk chain:
// Named background - uses bgXxx convention
getChalkBgChain('red', chalk) // → chalk.bgRed
// Hex background
getChalkBgChain('#1e1e1e', chalk) // → chalk.bgHex('#1e1e1e')
// RGB background
getChalkBgChain('rgb(30, 30, 30)', chalk) // → chalk.bgRgb(30, 30, 30)normalizeColorForCache(color)
Normalizes color strings for consistent cache keys:
// Hex normalization
normalizeColorForCache('#FF5733') // → '#ff5733' (lowercase)
// RGB normalization
normalizeColorForCache('rgb(255, 87, 51)') // → 'rgb(255,87,51)' (no spaces)
// Named colors unchanged
normalizeColorForCache('red') // → 'red'Performance Characteristics
- Named colors: O(1) - Direct property access
- Hex colors: O(1) - Single regex test + chalk call
- RGB colors: O(1) - Single regex test + validation + chalk call
- Pre-compiled regex: Patterns compiled once at module load time
Validation Rules
Hex Colors:
- Must match
/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/ - Case-insensitive
- Accepts 3-digit (
#RGB) or 6-digit (#RRGGBB) format
RGB Colors:
- Must match
/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i - Case-insensitive for
rgbkeyword - Each component must be 0-255 (inclusive)
- Spaces around values are optional
Named Colors:
- Must be valid chalk color names
- Case-sensitive (use lowercase:
'red', not'Red') - Checked via direct property access on chalk object
