LSP Server Plugins: Integrating Nine Official Language Servers and Custom LSP Configuration
Chapter 53: Theme and Appearance Plugins: CSS Variables, Dark Mode, and Brand Customization
53.1 The Role and Value of Appearance Plugins
Claude Code is a text-centric tool, but visual experience has a measurable impact on productivity. Extended use of default themes causes eye strain; enterprise users need tools that align with their brand visual system; different working environments — daytime vs. nighttime, high-contrast requirements, color-blindness-friendly modes — demand different color schemes.
Theme Plugins address exactly these needs. By injecting CSS variables and style overrides into Claude Code, they enable deep visual customization without modifying core code.
Unlike functional Plugins, Theme Plugins typically:
- Contain no MCP Server (no tool calls)
- Contain no Hooks (no lifecycle injection)
- Require no
network:outboundpermission - Are built around CSS files and a
theme.jsonconfiguration
53.2 Claude Code's CSS Variable System
Variable Layering Architecture
Claude Code's styling system is built on CSS Custom Properties (CSS variables), organized in three layers:
Base Tokens
├── Raw color values (e.g., --cc-color-blue-500: #3B82F6)
└── Raw dimensions (e.g., --cc-spacing-4: 16px)
Semantic Tokens
├── Functional colors (e.g., --cc-color-primary: var(--cc-color-blue-500))
└── Role colors (e.g., --cc-color-text-primary: #1a1a1a)
Component Tokens
├── Buttons (e.g., --cc-button-bg: var(--cc-color-primary))
└── Inputs (e.g., --cc-input-border: var(--cc-color-border))
Theme Plugins primarily operate at the semantic token layer, occasionally adjusting component tokens. Directly modifying base tokens affects too broad a scope and easily breaks visual consistency.
Core Semantic Variables
/* Text colors */
--cc-color-text-primary /* Main body text */
--cc-color-text-secondary /* Secondary text (labels, hints) */
--cc-color-text-tertiary /* Tertiary text (placeholders, disabled) */
--cc-color-text-inverse /* Inverted text (white on dark backgrounds) */
--cc-color-text-accent /* Accent text (links, highlights) */
--cc-color-text-error
--cc-color-text-success
--cc-color-text-warning
/* Background colors */
--cc-color-bg-primary /* Main background */
--cc-color-bg-secondary /* Secondary background (sidebar, panels) */
--cc-color-bg-tertiary /* Tertiary background (cards, dialogs) */
--cc-color-bg-elevated /* Elevated background (dropdowns, tooltips) */
--cc-color-bg-hover
--cc-color-bg-active
--cc-color-bg-code /* Code block background */
/* Border colors */
--cc-color-border
--cc-color-border-strong
--cc-color-border-focus /* Focus ring */
/* Brand colors */
--cc-color-primary
--cc-color-primary-hover
--cc-color-primary-active
/* Syntax highlighting */
--cc-syntax-keyword
--cc-syntax-string
--cc-syntax-comment
--cc-syntax-number
--cc-syntax-function
--cc-syntax-variable
--cc-syntax-operator
--cc-syntax-type
/* Typography */
--cc-font-family-sans
--cc-font-family-mono
--cc-font-size-base
--cc-line-height-base
/* Spacing & radius */
--cc-radius-sm
--cc-radius-md
--cc-radius-lg
53.3 Theme Plugin Project Structure
my-theme-plugin/
├── plugin.json
├── themes/
│ ├── light.css
│ ├── dark.css
│ └── high-contrast.css
├── theme.json
├── preview/
│ ├── light.png
│ └── dark.png
└── README.md
plugin.json for a Theme Plugin
{
"name": "acme-brand-theme",
"version": "1.0.0",
"description": "ACME Corporation brand theme for Claude Code",
"author": "ACME Design Team <[email protected]>",
"license": "MIT",
"keywords": ["theme", "brand", "corporate"],
"type": "theme",
"theme": {
"variants": [
{
"id": "acme-light",
"name": "ACME Light",
"appearance": "light",
"stylesheet": "./themes/light.css"
},
{
"id": "acme-dark",
"name": "ACME Dark",
"appearance": "dark",
"stylesheet": "./themes/dark.css"
},
{
"id": "acme-high-contrast",
"name": "ACME High Contrast",
"appearance": "dark",
"stylesheet": "./themes/high-contrast.css",
"tags": ["accessibility", "high-contrast"]
}
],
"defaultVariant": "acme-light",
"autoSwitch": {
"enabled": true,
"lightVariant": "acme-light",
"darkVariant": "acme-dark"
},
"previewImages": {
"acme-light": "./preview/light.png",
"acme-dark": "./preview/dark.png"
}
},
"engines": { "claude-code": ">=1.0.0" },
"permissions": []
}
The type: "theme" declaration tells Claude Code this is a pure appearance Plugin requiring no child processes.
53.4 Writing Theme CSS
Light Theme
/* themes/light.css — ACME Brand Light Theme */
:root[data-theme="acme-light"] {
/* Brand primary: deep ocean blue */
--cc-color-primary: #0047AB;
--cc-color-primary-hover: #003580;
--cc-color-primary-active: #002460;
/* Backgrounds */
--cc-color-bg-primary: #FFFFFF;
--cc-color-bg-secondary: #F5F7FA;
--cc-color-bg-tertiary: #EDF0F5;
--cc-color-bg-elevated: #FFFFFF;
--cc-color-bg-hover: rgba(0, 71, 171, 0.06);
--cc-color-bg-active: rgba(0, 71, 171, 0.12);
--cc-color-bg-code: #F8F9FC;
/* Text */
--cc-color-text-primary: #1A1D23;
--cc-color-text-secondary: #4B5568;
--cc-color-text-tertiary: #9AA5B4;
--cc-color-text-inverse: #FFFFFF;
--cc-color-text-accent: #0047AB;
/* Borders */
--cc-color-border: #D1D9E6;
--cc-color-border-strong: #A8B4C8;
--cc-color-border-focus: #0047AB;
/* Status */
--cc-color-text-error: #C0392B;
--cc-color-text-success: #1A7340;
--cc-color-text-warning: #C17D00;
/* Syntax highlighting */
--cc-syntax-keyword: #0047AB;
--cc-syntax-string: #1A7340;
--cc-syntax-comment: #9AA5B4;
--cc-syntax-number: #C17D00;
--cc-syntax-function: #6B3FA0;
--cc-syntax-variable: #1A1D23;
--cc-syntax-operator: #4B5568;
--cc-syntax-type: #B83C1E;
/* Typography */
--cc-font-family-sans: 'Inter', 'SF Pro Display', -apple-system, sans-serif;
--cc-font-family-mono: 'JetBrains Mono', 'Fira Code', monospace;
--cc-font-size-base: 14px;
--cc-line-height-base: 1.6;
/* Radius */
--cc-radius-sm: 4px;
--cc-radius-md: 6px;
--cc-radius-lg: 12px;
}
Dark Theme
/* themes/dark.css — ACME Brand Dark Theme */
:root[data-theme="acme-dark"] {
/* Brand primary: lightened for dark backgrounds */
--cc-color-primary: #4D9FFF;
--cc-color-primary-hover: #6FB3FF;
--cc-color-primary-active: #91C5FF;
/* Backgrounds */
--cc-color-bg-primary: #0D1117;
--cc-color-bg-secondary: #161B22;
--cc-color-bg-tertiary: #21262D;
--cc-color-bg-elevated: #2D333B;
--cc-color-bg-hover: rgba(77, 159, 255, 0.08);
--cc-color-bg-active: rgba(77, 159, 255, 0.16);
--cc-color-bg-code: #161B22;
/* Text */
--cc-color-text-primary: #E6EDF3;
--cc-color-text-secondary: #8B949E;
--cc-color-text-tertiary: #484F58;
--cc-color-text-inverse: #0D1117;
--cc-color-text-accent: #4D9FFF;
/* Borders */
--cc-color-border: #30363D;
--cc-color-border-strong: #484F58;
--cc-color-border-focus: #4D9FFF;
/* Status */
--cc-color-text-error: #F85149;
--cc-color-text-success: #3FB950;
--cc-color-text-warning: #D29922;
/* Syntax highlighting */
--cc-syntax-keyword: #FF7B72;
--cc-syntax-string: #A5D6FF;
--cc-syntax-comment: #8B949E;
--cc-syntax-number: #F2CC60;
--cc-syntax-function: #D2A8FF;
--cc-syntax-variable: #E6EDF3;
--cc-syntax-operator: #8B949E;
--cc-syntax-type: #FFA657;
}
High-Contrast Theme
High-contrast theme design prioritizes readability over aesthetics:
/* themes/high-contrast.css */
:root[data-theme="acme-high-contrast"] {
--cc-color-bg-primary: #000000;
--cc-color-bg-secondary: #0A0A0A;
--cc-color-bg-code: #000000;
/* Pure white text — guarantees WCAG AAA contrast */
--cc-color-text-primary: #FFFFFF;
--cc-color-text-secondary: #E0E0E0;
--cc-color-text-tertiary: #B0B0B0;
/* Bright yellow primary — maximum visibility */
--cc-color-primary: #FFD700;
--cc-color-primary-hover: #FFEA00;
--cc-color-text-accent: #FFD700;
--cc-color-border: #808080;
--cc-color-border-strong: #C0C0C0;
--cc-color-border-focus: #FFD700;
--cc-color-text-error: #FF4444;
--cc-color-text-success: #00FF88;
--cc-color-text-warning: #FFAA00;
/* Larger base font size improves readability */
--cc-font-size-base: 15px;
--cc-line-height-base: 1.8;
}
53.5 Dark Mode Auto-Switching
Claude Code monitors the prefers-color-scheme media query and automatically switches theme variants when the system dark mode setting changes. Configuration is in plugin.json under theme.autoSwitch.
Users can also manually lock a specific variant:
# Set theme manually
claude config set theme acme-dark
# Return to automatic mode
claude config set theme auto
53.6 Font Customization
Built-in vs. External Fonts
Built-in fonts: Claude Code bundles common monospace fonts (JetBrains Mono, Fira Code, Cascadia Code) and sans-serif fonts (Inter, SF Pro). Reference them directly in CSS variables.
External fonts: If your brand font is not in the built-in list, declare font assets in plugin.json:
{
"theme": {
"fonts": [
{
"family": "ACME Sans",
"sources": [
{
"url": "./fonts/ACMESans-Regular.woff2",
"weight": 400,
"style": "normal"
},
{
"url": "./fonts/ACMESans-Bold.woff2",
"weight": 700,
"style": "normal"
}
]
}
]
}
}
Monospace Font Best Practices
/* Always provide a fallback stack */
--cc-font-family-mono:
'JetBrains Mono', /* preferred: ligature support */
'Fira Code', /* fallback: open-source, cross-platform */
'Cascadia Code', /* Windows fallback */
'SF Mono', /* macOS system fallback */
'Consolas', /* Windows system fallback */
monospace;
/* Enable ligatures if supported */
font-feature-settings: "liga" 1, "calt" 1;
53.7 Component-Level Customization
For customizations that standard CSS variables can't cover, Theme Plugins support component-level CSS overrides:
/* Append to the end of your theme CSS */
/* Custom sidebar width */
.cc-sidebar {
width: 280px;
}
/* Custom assistant message bubble */
.cc-message-bubble--assistant {
border-left: 3px solid var(--cc-color-primary);
border-radius: 0 var(--cc-radius-md) var(--cc-radius-md) 0;
}
/* Custom tool call display card */
.cc-tool-call-card {
background: var(--cc-color-bg-code);
border: 1px solid var(--cc-color-border);
font-family: var(--cc-font-family-mono);
font-size: 12px;
}
Important caveat: Claude Code's internal CSS class names may change across versions. Always specify a precise version range in engines.claude-code and test style compatibility after upgrading.
53.8 Preview Image Specifications
Marketplace listing preview images directly influence installation decisions:
Dimensions: 1280 × 800 pixels (16:10 ratio)
Format: PNG, JPEG, or WebP (PNG recommended for detail)
Max file size: 500 KB
Content requirements:
├── Show the conversation interface (user message + Claude reply)
├── Show a code block (demonstrates syntax highlighting colors)
├── Show the sidebar (demonstrates overall layout and color tone)
└── Must not contain real personal information or proprietary content
53.9 Accessibility Validation
WCAG 2.1 AA standards require:
- Normal text: contrast ratio ≥ 4.5:1
- Large text (18px bold or 24px normal): contrast ratio ≥ 3:1
- Interactive component borders: contrast ratio ≥ 3:1
claude-plugin theme check-accessibility ./themes/light.css
# Checking accessibility for acme-light theme...
# ✓ --cc-color-text-primary on --cc-color-bg-primary: 12.4:1 (AAA)
# ✓ --cc-color-text-secondary on --cc-color-bg-primary: 5.2:1 (AA)
# ✗ --cc-color-text-tertiary on --cc-color-bg-primary: 2.8:1 (FAIL)
# ↳ Required: 4.5:1 for normal text
# ↳ Suggestion: Darken --cc-color-text-tertiary to #767676 or darker
Any AA-level contrast failure causes marketplace review rejection. Run this check before every submission.
Summary
Theme Plugins achieve non-invasive visual customization through Claude Code's CSS variable system. The key is understanding the three-layer variable hierarchy — Base Tokens → Semantic Tokens → Component Tokens — and operating primarily at the semantic layer. Dark mode auto-switching, custom fonts, and high-contrast accessibility support are essential features of a high-quality Theme Plugin. Pre-publication accessibility validation is not just a review requirement; it is a basic respect for all users. The next chapter shifts to the technically deeper territory of LSP Plugin development.