# How Zed's Theme System Supports Custom Themes and Syntax Highlighting

> Discover how Zed's theme system uses JSON to support custom themes and syntax highlighting, offering UI palette customization and runtime merging for personalized editor experiences.

- Repository: [Zed Industries/zed](https://github.com/zed-industries/zed)
- Tags: deep-dive
- Published: 2026-03-01

---

**Zed's theme system utilizes a JSON-driven schema to define UI palettes and syntax highlighting rules, enabling custom themes through the `ThemeRegistry` and runtime merging of user overrides.**

Zed's theme system provides a flexible, JSON-based architecture for customizing UI colors and syntax highlighting in the zed-industries/zed editor. Built around the `crates/theme` crate, it supports both user-defined themes and extension-bundled themes through a registry-based loading mechanism that validates against the official schema at `https://zed.dev/schema/themes/v0.2.0.json`.

## Core Architecture of Zed's Theme System

The theming infrastructure is organized into three distinct layers within the `crates/theme` directory, separating data models, loading logic, and syntax highlighting definitions.

### Theme Loading and Registry

The `ThemeRegistry` struct in [`crates/theme/src/registry.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme/src/registry.rs) (lines 22–58) serves as the central authority for theme discovery and storage. On initialization, the registry walks the user theme directory and extension folders, parsing each JSON file into a `ThemeMeta` struct stored in a `HashMap<String, ThemeMeta>`. Each entry contains a `ThemeFamily` grouping light and dark variants, along with a lazily-computed `Theme` instance that is materialized only when selected.

### Theme Data Model

The `Theme` struct defined in [`crates/theme/src/theme.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme/src/theme.rs) (lines 336–374) encapsulates all visual styling data through a `ThemeStyles` object. This structure includes:

- **`colors: ThemeColors`** – UI element colors for backgrounds, borders, and accents
- **`syntax: Arc<SyntaxTheme>`** – The syntax highlighting definition shared across editor instances
- **Status bar, title bar, and accent style groups** – Context-specific UI styling

### Syntax Highlighting Engine

Syntax coloring is governed by the `SyntaxTheme` type in [`crates/theme/src/styles/syntax.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme/src/styles/syntax.rs). This file defines the `HighlightStyle` struct and the merging logic that combines built-in defaults with user customizations. The `SyntaxTheme::merge` method (lines 60–68) takes a vector of `(String, HighlightStyle)` pairs and produces a new theme instance where custom definitions override base values. At runtime, the editor queries specific token colors via `Theme::syntax_color(name)` (lines 386–387 in [`theme.rs`](https://github.com/zed-industries/zed/blob/main/theme.rs)), which delegates to the underlying `SyntaxTheme`.

## Creating and Loading Custom Themes

Zed supports custom themes through JSON configuration files placed in specific user directories, automatically registering them on startup without requiring a restart.

### JSON Schema and File Structure

Custom themes must conform to version `v0.2.0` of the Zed theme schema. A valid theme JSON file defines a top-level object containing:

- **`name`** and **`type`** (light or dark) – Metadata for the theme selector
- **`colors`** – A map of UI color keys to hex values
- **`syntax`** – A map of token types to `HighlightStyle` objects defining color, italic, bold, and underline properties

### User Theme Directories

Zed scans for theme files in platform-specific configuration directories. On Linux and macOS, place `.json` theme files in `~/.config/zed/themes`. On Windows, use `%APPDATA%\Zed\themes`. The `ThemeRegistry::load_all()` method recursively searches these paths during initialization, validating each file against the schema before adding it to the registry's internal `HashMap`.

### Runtime Registration

Once loaded, themes appear immediately in the Theme Selector UI. The registry resolves light and dark family groupings, allowing users to switch between variants without restarting the editor. This hot-loading capability is implemented through the lazy evaluation of `Theme` instances from their `ThemeMeta` descriptors stored in the registry.

## Merging Theme Overrides and Extensions

Beyond static JSON files, Zed supports dynamic theme customization through settings overrides and extension bundles, enabling granular control without modifying core theme files.

### User Settings Overrides

Users can apply targeted syntax highlighting modifications through the `theme_overrides` setting in [`settings.json`](https://github.com/zed-industries/zed/blob/main/settings.json). The `ThemeSettings::apply_overrides` function in [`crates/theme/src/settings.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme/src/settings.rs) (lines 571–573) processes these overrides by calling `SyntaxTheme::merge` with the user-provided `(token, HighlightStyle)` pairs. This produces a new `Arc<SyntaxTheme>` that supersedes the base theme's defaults while preserving unmodified token styles.

### Extension-Based Themes

Extensions can bundle themes by including JSON files in an `extensions/<name>/themes/` directory. The `theme_extension::ThemeRegistryProxy` struct in [`crates/theme_extension/src/theme_extension.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme_extension/src/theme_extension.rs) (line 21) provides the `register_theme_from_path` method, which extensions call during initialization to register bundled themes at runtime. This proxy interface makes extension themes immediately available in the Theme Selector without requiring a Zed restart, effectively hot-swapping the theme registry's contents.

## Key Files Reference

The following source files implement Zed's theming infrastructure:

| File | Role | Location |
|------|------|----------|
| [`crates/theme/src/theme.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme/src/theme.rs) | Core `Theme` and `ThemeFamily` structs, UI-style accessors | [`crates/theme/src/theme.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme/src/theme.rs) |
| [`crates/theme/src/registry.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme/src/registry.rs) | Loading, parsing, and storing theme metadata (`ThemeRegistry`) | [`crates/theme/src/registry.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme/src/registry.rs) |
| [`crates/theme/src/styles/syntax.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme/src/styles/syntax.rs) | Definition and merging of `SyntaxTheme` and `HighlightStyle` | [`crates/theme/src/styles/syntax.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme/src/styles/syntax.rs) |
| [`crates/theme/src/settings.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme/src/settings.rs) | Handling of `theme_overrides` from user settings | [`crates/theme/src/settings.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme/src/settings.rs) |
| [`crates/theme_extension/src/theme_extension.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme_extension/src/theme_extension.rs) | Bridge for extensions to register bundled themes | [`crates/theme_extension/src/theme_extension.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme_extension/src/theme_extension.rs) |
| [`docs/src/extensions/themes.md`](https://github.com/zed-industries/zed/blob/main/docs/src/extensions/themes.md) | Documentation of the JSON schema and extension layout | [`docs/src/extensions/themes.md`](https://github.com/zed-industries/zed/blob/main/docs/src/extensions/themes.md) |
| [`docs/src/themes.md`](https://github.com/zed-industries/zed/blob/main/docs/src/themes.md) | User-facing guide on installing and creating custom themes | [`docs/src/themes.md`](https://github.com/zed-industries/zed/blob/main/docs/src/themes.md) |

## Summary

- Zed's theme system relies on a **JSON-driven schema** (`v0.2.0`) that defines UI colors in the `colors` field and syntax highlighting in the `syntax` field.
- The **`ThemeRegistry`** in [`crates/theme/src/registry.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme/src/registry.rs) handles automatic discovery and validation of theme files from `~/.config/zed/themes` or extension directories.
- **Syntax highlighting customization** occurs through `SyntaxTheme::merge` in [`crates/theme/src/styles/syntax.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme/src/styles/syntax.rs), which combines base themes with user `theme_overrides` or extension contributions.
- **Extensions** register themes at runtime via `ThemeRegistryProxy` in [`crates/theme_extension/src/theme_extension.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme_extension/src/theme_extension.rs), enabling hot-loading without restart.

## Frequently Asked Questions

### How do I create a custom theme for Zed?

Create a JSON file following the schema at `https://zed.dev/schema/themes/v0.2.0.json`, defining UI colors under `"colors"` and syntax styles under `"syntax"`. Place this file in `~/.config/zed/themes` on Linux/macOS or `%APPDATA%\Zed\themes` on Windows, and Zed will automatically load it on startup via the `ThemeRegistry`.

### Can I override specific syntax highlighting colors without creating a full theme?

Yes, use the `theme_overrides` setting in your [`settings.json`](https://github.com/zed-industries/zed/blob/main/settings.json) to specify individual token colors and styles. These overrides are merged with your active theme at runtime via `SyntaxTheme::merge` in [`crates/theme/src/styles/syntax.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme/src/styles/syntax.rs), allowing targeted customization without duplicating the entire theme definition.

### How do extensions register custom themes in Zed?

Extensions bundle theme JSON files in an `extensions/<name>/themes/` directory and use the `ThemeRegistryProxy` struct from [`crates/theme_extension/src/theme_extension.rs`](https://github.com/zed-industries/zed/blob/main/crates/theme_extension/src/theme_extension.rs) (line 21) to register them at runtime. This makes the themes immediately available in the Theme Selector without requiring a Zed restart.

### What JSON schema version should I use for Zed themes?

Use version `v0.2.0` of the Zed theme schema, accessible at `https://zed.dev/schema/themes/v0.2.0.json`. This schema defines the required structure for UI color definitions, syntax highlighting rules, and theme metadata including the theme name and type (light or dark).