What is theme.json File in WordPress and How to Use It: A Comprehensive Guide

In the ever-evolving landscape of WordPress, the introduction of the block editor (Gutenberg) marked a paradigm shift in how users create and design content. As WordPress continues to embrace full-site editing (FSE), a critical tool has emerged to streamline theme development and customization: theme.json.

Gone are the days of relying solely on style.css and functions.php to define a theme’s appearance and behavior. With theme.json, developers and designers can now centralize configuration for global styles, block settings, typography, colors, and more—all in a single, human-readable JSON file. This not only simplifies theme development but also ensures consistency across the site, enhances compatibility with the block editor, and reduces the need for custom CSS.

Whether you’re building a custom block theme, modifying an existing one, or simply curious about modern WordPress theming, understanding theme.json is essential. In this guide, we’ll dive deep into what theme.json is, its core purpose, structure, key features, and step-by-step instructions for creating and using it effectively.

Table of Contents#

  1. What is theme.json?
  2. Core Purpose and Benefits of theme.json
  3. Key Features of theme.json
  4. Structure of theme.json: Top-Level Keys Explained
  5. How to Create and Use theme.json: A Step-by-Step Guide
  6. Advanced Customization with theme.json
  7. Best Practices for Working with theme.json
  8. Troubleshooting Common theme.json Issues
  9. Conclusion
  10. References

What is theme.json?#

theme.json is a configuration file introduced in WordPress 5.8 (released July 2021) to standardize and simplify the customization of block themes. It uses the JSON (JavaScript Object Notation) format to define global settings, styles, and templates, acting as a single source of truth for a theme’s design system.

Key Context: Block Themes vs. Classic Themes#

To understand theme.json, it’s important to distinguish between block themes and classic themes:

  • Classic themes rely on PHP templates (e.g., header.php, single.php), style.css, and functions.php for layout and styling. They often use custom CSS classes and hooks to modify block behavior.
  • Block themes (introduced with WordPress 5.9) leverage the block editor for full-site editing, using block-based templates (e.g., index.html, single.html) stored in the templates/ and parts/ directories. theme.json is a core component of block themes, replacing much of the CSS and PHP configuration from classic themes.

In short, theme.json is the bridge between a block theme’s design system and the block editor, enabling granular control over how blocks look and behave—both in the editor and on the front end.

Core Purpose and Benefits of theme.json#

theme.json was designed to solve several pain points in traditional WordPress theme development. Here’s why it matters:

1. Centralized Configuration#

Instead of scattering styles across style.css, functions.php, and template files, theme.json consolidates all design-related settings (colors, typography, spacing, etc.) in one file. This makes it easier to maintain and update a theme’s design system.

2. Consistency Across Editor and Front End#

In classic themes, discrepancies often arose between how content looked in the editor (Gutenberg) and on the front end. theme.json ensures styles defined in the file are applied both in the editor and on the front end, eliminating “what you see is what you get” (WYSIWYG) gaps.

3. Reduced Reliance on Custom CSS#

By defining global styles and block-specific settings in theme.json, you can minimize custom CSS. WordPress automatically generates CSS variables from theme.json settings, reducing the need for manual styling.

4. Enhanced Accessibility#

theme.json includes built-in support for accessibility best practices, such as enforcing contrast ratios for text and background colors. The block editor uses these settings to guide users toward accessible design choices.

5. Simplified Child Theme Development#

Child themes can override or extend parent theme settings by including their own theme.json file. This avoids the need to override entire CSS files, making child theme customization more modular.

6. Compatibility with Future WordPress Features#

As WordPress continues to expand full-site editing, theme.json is becoming the standard for theme configuration. Using it ensures your theme will be compatible with upcoming FSE enhancements.

Key Features of theme.json#

theme.json offers a wide range of features to customize every aspect of a block theme. Let’s explore its most powerful capabilities:

1. Global Settings#

Define foundational design constraints, such as which features are enabled for blocks (e.g., custom colors, font sizes) and default values for properties like spacing or typography.

Examples of settings:

  • Enabling/disabling custom color pickers for blocks.
  • Defining a default font size for paragraph blocks.
  • Restricting block alignment options (e.g., disabling “wide” alignment).

2. Global Styles#

Apply universal styles to elements like the body, headings, or links, and to specific blocks (e.g., buttons, images). These styles are automatically injected into both the editor and front end.

Examples of styles:

  • Setting a global background color for the body.
  • Defining font families for headings (H1–H6).
  • Customizing the border radius of all button blocks.

3. Block-Specific Customization#

Override global settings and styles for individual blocks. For example, you could disable custom colors for paragraph blocks but enable them for button blocks, or set a unique font size for quote blocks.

4. Custom Templates and Template Parts#

Define which block templates (e.g., single.html, archive.html) and template parts (e.g., header.html, footer.html) are available in the Site Editor.

5. Theme Supports#

Declare support for WordPress features (e.g., align-wide, responsive-embeds) directly in theme.json, replacing the need for add_theme_support() in functions.php.

6. CSS Variables (Custom Properties)#

theme.json automatically generates CSS variables for settings like colors and font sizes, which can be reused in custom CSS. For example, a color defined as primary in theme.json becomes var(--wp--preset--color--primary) in CSS.

Structure of theme.json: Top-Level Keys Explained#

theme.json uses a hierarchical structure with top-level keys that organize its functionality. Below is a breakdown of the most important keys, along with their purposes:

KeyDescription
$schemaURL to the JSON schema for validation (e.g., https://schemas.wp.org/trunk/theme.json). Ensures your file follows the correct format.
versionThe theme.json specification version (e.g., 2 for WordPress 5.9+). Required for compatibility.
settingsDefines global settings (e.g., colors, typography, spacing) and block-specific settings.
stylesDefines global styles (e.g., body background, heading fonts) and block-specific styles.
templatePartsLists template parts (e.g., header, footer) available in the Site Editor.
templatesLists templates (e.g., index, single) available in the Site Editor.
customTemplatesDefines custom templates for specific post types (e.g., a “portfolio” template for a custom post type).
postTypesCustomizes settings/styles for specific post types (e.g., different styles for pages vs. posts).
patternsRegisters block patterns (reusable block combinations) directly in the theme.

Sample theme.json Skeleton#

To visualize this structure, here’s a simplified theme.json with key sections:

{  
  "$schema": "https://schemas.wp.org/trunk/theme.json",  
  "version": 2,  
  "settings": {  
    "color": {  
      "palette": [  
        { "slug": "primary", "color": "#2563eb", "name": "Primary" },  
        { "slug": "secondary", "color": "#4f46e5", "name": "Secondary" }  
      ]  
    },  
    "typography": {  
      "fontSizes": [  
        { "slug": "small", "size": "1rem", "name": "Small" },  
        { "slug": "medium", "size": "1.25rem", "name": "Medium" }  
      ]  
    }  
  },  
  "styles": {  
    "color": { "background": "var(--wp--preset--color--primary)" },  
    "typography": { "fontSize": "var(--wp--preset--font-size--medium)" },  
    "blocks": {  
      "core/button": {  
        "color": { "background": "var(--wp--preset--color--secondary)" }  
      }  
    }  
  }  
}  

How to Create and Use theme.json: A Step-by-Step Guide#

Creating a theme.json file is straightforward. Follow these steps to build a basic configuration for a block theme:

Step 1: Set Up a Block Theme#

theme.json is only used in block themes. If you’re starting from scratch, create a minimal block theme with the following structure:

my-block-theme/  
├── style.css  
├── theme.json  
├── templates/  
│   └── index.html  
└── parts/  
    ├── header.html  
    └── footer.html  
  • style.css: Required for theme metadata (name, author, etc.).
  • templates/: Contains block-based templates (e.g., index.html for the homepage).
  • parts/: Contains template parts (e.g., header.html for the site header).

Step 2: Create the theme.json File#

Add theme.json to your theme’s root directory. Start with the basic structure, including the $schema (for validation) and version (critical for compatibility):

{  
  "$schema": "https://schemas.wp.org/trunk/theme.json",  
  "version": 2  
}  
  • $schema: Ensures your file adheres to the official theme.json format (most code editors will auto-validate with this URL).
  • version: Use 2 for WordPress 5.9+ (the latest version as of 2023). Older versions (e.g., 1) are deprecated.

Step 3: Define Global Settings#

The settings key controls which features are enabled and their default values. Let’s add color and typography presets, which will appear in the block editor’s sidebar.

Example: Color Palette#

Define a custom color palette so users can select pre-approved colors for blocks:

"settings": {  
  "color": {  
    "custom": false, // Disable custom color picker (use only presets)  
    "palette": [  
      {  
        "slug": "primary",  
        "color": "#2563eb", // Blue  
        "name": "Primary"  
      },  
      {  
        "slug": "secondary",  
        "color": "#4f46e5", // Indigo  
        "name": "Secondary"  
      },  
      {  
        "slug": "text",  
        "color": "#111827", // Dark gray  
        "name": "Text"  
      }  
    ]  
  }  
}  

Example: Typography Settings#

Add font sizes and families:

"settings": {  
  "typography": {  
    "customFontSize": false, // Disable custom font size input  
    "fontSizes": [  
      {  
        "slug": "small",  
        "size": "1rem", // 16px  
        "name": "Small"  
      },  
      {  
        "slug": "medium",  
        "size": "1.25rem", // 20px  
        "name": "Medium"  
      },  
      {  
        "slug": "large",  
        "size": "1.75rem", // 28px  
        "name": "Large"  
      }  
    ],  
    "fontFamilies": [  
      {  
        "slug": "sans",  
        "fontFamily": "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",  
        "name": "Sans Serif"  
      }  
    ]  
  }  
}  

Step 4: Add Global Styles#

The styles key defines how elements and blocks should look by default. Let’s set a global background color, body font, and heading styles.

Example: Global Body Styles#

"styles": {  
  "color": {  
    "background": "white", // Page background  
    "text": "var(--wp--preset--color--text)" // Text color (uses the "text" preset)  
  },  
  "typography": {  
    "fontFamily": "var(--wp--preset--font-family--sans)", // Default font family  
    "fontSize": "var(--wp--preset--font-size--medium)" // Default font size  
  }  
}  

Example: Heading Styles#

Customize H1–H6 tags globally:

"styles": {  
  "elements": {  
    "h1": {  
      "typography": {  
        "fontSize": "var(--wp--preset--font-size--large)",  
        "fontWeight": "700"  
      },  
      "color": { "text": "var(--wp--preset--color--primary)" }  
    },  
    "h2": {  
      "typography": {  
        "fontSize": "1.5rem",  
        "fontWeight": "600"  
      }  
    }  
  }  
}  

Step 5: Block-Specific Customization#

Override global settings/styles for individual blocks using the blocks key under settings or styles.

Example: Customize Button Blocks#

Disable custom colors for buttons and set a default background color:

"settings": {  
  "blocks": {  
    "core/button": {  
      "color": {  
        "customBackground": false, // Disable custom background color  
        "customText": false // Disable custom text color  
      }  
    }  
  }  
},  
"styles": {  
  "blocks": {  
    "core/button": {  
      "color": {  
        "background": "var(--wp--preset--color--secondary)",  
        "text": "white"  
      },  
      "typography": { "fontWeight": "600" },  
      "spacing": { "padding": "1rem 2rem" }  
    }  
  }  
}  

Step 6: Test in WordPress#

  1. Zip your theme folder and install it in WordPress (Appearance > Themes > Add New).
  2. Activate the theme.
  3. Navigate to Appearance > Editor to open the Site Editor. You’ll see your theme.json styles applied in the editor.
  4. Create a new post or page; blocks like buttons and headings will use the presets and styles defined in theme.json.

Advanced Customization with theme.json#

Once you’ve mastered the basics, explore these advanced techniques to unlock theme.json’s full potential:

1. Using CSS Variables (Custom Properties)#

theme.json automatically converts presets (colors, font sizes, etc.) into CSS variables, which you can reuse in custom CSS or template files. For example:

/* In style.css */  
.my-custom-class {  
  color: var(--wp--preset--color--primary);  
  font-size: var(--wp--preset--font-size--large);  
}  

2. Conditional Styles with context#

Use the context key to apply styles only in specific contexts (e.g., front end vs. editor, or mobile vs. desktop).

Example: Dark mode for the editor only:

"styles": {  
  "context": "editor",  
  "color": { "background": "#1a1a1a", "text": "white" }  
}  

3. Custom Spacing Presets#

Define spacing presets (e.g., for margins/padding) and use them across blocks:

"settings": {  
  "spacing": {  
    "units": [ "px", "rem", "em" ],  
    "presets": [  
      { "slug": "small", "size": "1rem", "name": "Small" },  
      { "slug": "medium", "size": "2rem", "name": "Medium" }  
    ]  
  }  
},  
"styles": {  
  "blocks": {  
    "core/paragraph": {  
      "spacing": { "margin": { "bottom": "var(--wp--preset--spacing--small)" } }  
    }  
  }  
}  

4. Post Type-Specific Settings#

Customize styles for specific post types (e.g., different colors for pages vs. posts) using the postTypes key:

"postTypes": {  
  "page": {  
    "styles": {  
      "color": { "background": "var(--wp--preset--color--secondary)" }  
    }  
  }  
}  

Best Practices for Working with theme.json#

To ensure your theme.json is maintainable and effective, follow these best practices:

1. Validate with the Schema#

Always include the $schema URL to enable auto-validation in code editors like VS Code. This catches syntax errors early:

"$schema": "https://schemas.wp.org/trunk/theme.json"  

2. Use Semantic Slugs for Presets#

Choose descriptive slugs (e.g., primary, small) for colors, font sizes, and spacing. This makes variables like var(--wp--preset--color--primary) intuitive.

3. Avoid Redundancy#

Leverage CSS variables instead of hardcoding values. For example, use var(--wp--preset--color--primary) instead of #2563eb in multiple places.

4. Test Across Environments#

Always test theme.json changes in both the block editor and on the front end. Use browser dev tools to inspect generated CSS (look for classes starting with wp-).

5. Document Customizations#

Add comments to theme.json (using a tool like JSON5 if needed) to explain complex settings, especially for collaborative projects.

6. Stay Updated on Version Changes#

theme.json evolves with WordPress updates. Check the official documentation when upgrading WordPress to ensure compatibility.

Troubleshooting Common theme.json Issues#

Even with careful setup, you may encounter issues. Here’s how to resolve the most common problems:

Issue 1: Styles Not Applying#

  • Check the version key: Use 2 for WordPress 5.9+. Older versions (e.g., 1) have deprecated features.
  • Validate JSON syntax: Use a tool like JSONLint to catch missing commas or brackets.
  • Clear the cache: WordPress caches theme.json; flush the site cache (e.g., via WP Rocket or Litespeed) if changes aren’t showing.

Issue 2: Block Settings Not Working#

  • Use the correct block name: Block slugs are case-sensitive and follow the format core/block-name (e.g., core/paragraph, not paragraph).
  • Check for nested settings: Ensure block-specific settings are nested under settings.blocks.[block-name].

Issue 3: Editor vs. Front-End Discrepancies#

  • Avoid !important in custom CSS: This can override theme.json styles in the editor but not the front end.
  • Use context wisely: If styles differ, verify you’re not using context: "editor" or context: "front" unintentionally.

Issue 4: Deprecated Keys#

WordPress occasionally deprecates theme.json keys (e.g., customTemplates replaced templates in version 2). Refer to the changelog for updates.

Conclusion#

theme.json is a game-changer for WordPress theme development, offering a centralized, intuitive way to configure block themes. By defining global settings, styles, and block behavior in a single file, you can create consistent, maintainable, and future-proof themes that work seamlessly with the block editor and full-site editing.

Whether you’re building a simple blog theme or a complex e-commerce site, theme.json empowers you to take control of your design system without writing endless CSS. As WordPress continues to prioritize block-based development, mastering theme.json is essential for any theme developer.

References#