Theme.json is the single most important file in a WordPress block theme. It is the configuration file that controls your site’s global design system, colors, typography, spacing, layout, and per-block style defaults, all defined declaratively in JSON rather than scattered across PHP files, stylesheets, and Customizer settings. Understanding every section of theme.json is essential for anyone building or maintaining block themes in 2026. This guide covers the complete schema, explains what each setting does, and shows you how to combine them into a coherent, production-ready design system.

This is a reference guide as much as a tutorial. Bookmark it and return to it when you need to remember what a specific theme.json property does, what values it accepts, or how it interacts with other settings. The guide follows the theme.json v3 schema introduced in WordPress 6.6 and expanded in 6.7 and 6.8.

The theme.json Structure: Top-Level Keys

Every theme.json file follows a defined schema. At the top level, there are four keys you need to understand: $schema, version, settings, and styles. Two additional top-level keys, customTemplates and templateParts, are used to declare templates and template parts that WordPress should recognize.

{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 3,
  "settings": { },
  "styles": { },
  "customTemplates": [ ],
  "templateParts": [ ]
}

The $schema key points to the JSON schema definition, which enables IntelliSense and validation in editors like VS Code. Always include it. The version key tells WordPress which schema version this file uses, use version 3 for all new theme development in 2026. Settings and styles are where all the meaningful configuration lives.

The settings Object: Configuring Global Design Tokens

The settings object is where you define your design tokens and control what capabilities the block editor exposes to users. Think of it as the “what exists” layer, you are declaring what colors, font sizes, spacing values, and layout widths are available in your design system.

theme.json global settings and styles, complete reference guide

settings.color

The color settings section defines your color palette, gradient presets, and controls which color-related UI panels appear in the block editor. Here is what each property does:

  • settings.color.palette, Array of color objects, each with name, slug, and color. These appear in every color picker in the editor. The slug becomes a CSS custom property: a slug of “primary” becomes var(--wp--preset--color--primary)
  • settings.color.gradients, Array of gradient presets available in gradient pickers. Each needs name, slug, and gradient (a valid CSS gradient string)
  • settings.color.duotone, Array of duotone filter presets for the Image and Cover blocks. Each needs name, slug, and colors (an array of two hex colors)
  • settings.color.custom, Boolean. Set to false to remove the custom color picker from the editor, forcing users to only pick from your defined palette
  • settings.color.customGradient, Boolean. Set to false to remove the custom gradient editor
  • settings.color.customDuotone, Boolean. Set to false to disable custom duotone creation
  • settings.color.defaultPalette, Boolean. Set to false to hide WordPress’s built-in default color palette from the editor
  • settings.color.defaultGradients, Boolean. Set to false to hide WordPress’s built-in gradient presets
  • settings.color.background, Boolean. Controls whether the background color panel appears for blocks
  • settings.color.text, Boolean. Controls whether the text color panel appears for blocks
  • settings.color.link, Boolean. Controls whether the link color panel appears for blocks that support it

settings.typography

Typography settings control font families, font sizes, line heights, and letter spacing. This is one of the richest sections of theme.json and the one most likely to need careful configuration for a production theme. For a full breakdown of how typography presets work with fluid type, see our complete guide to typography presets in theme.json.

  • settings.typography.fontFamilies, Array of font family objects. Each has name, slug, and fontFamily (CSS font stack). For self-hosted fonts, include a fontFace array with declarations for each weight and style
  • settings.typography.fontSizes, Array of font size presets. Each has name, slug, size (CSS value), and optionally fluid for responsive scaling with CSS clamp()
  • settings.typography.fluid, Boolean or object. Set to true to enable fluid typography globally. Set as an object to configure min and max viewport widths for the clamp() calculation
  • settings.typography.customFontSize, Boolean. Set to false to remove the custom font size input from the editor
  • settings.typography.lineHeight, Boolean. Set to true to enable the line height control in the typography panel
  • settings.typography.letterSpacing, Boolean. Set to true to enable the letter spacing control
  • settings.typography.textDecoration, Boolean. Controls whether text decoration (underline, strikethrough) options appear
  • settings.typography.textTransform, Boolean. Controls whether text transform (uppercase, lowercase, capitalize) options appear
  • settings.typography.fontStyle, Boolean. Controls whether the italic/normal toggle appears
  • settings.typography.fontWeight, Boolean. Controls whether the font weight selector appears
  • settings.typography.dropCap, Boolean. Controls whether the drop cap option appears in Paragraph block settings

settings.spacing

Spacing settings define your spacing scale and control padding, margin, and gap controls in the editor. Consistent spacing is one of the most impactful design decisions for a coherent block theme, using a defined scale prevents arbitrary spacing choices that create visual inconsistency. Fluid spacing that scales with viewport width is covered in our guide to fluid typography and spacing with theme.json.

  • settings.spacing.spacingSizes, Array of spacing preset objects. Each has name, slug, and size. The slug becomes a CSS custom property: “40” becomes var(--wp--preset--spacing--40). Following WordPress core’s numbering convention (10, 20, 30, 40, 50, 60, 70, 80) is recommended for third-party compatibility
  • settings.spacing.units, Array of CSS units available in the spacing controls. Defaults to [“px”, “em”, “rem”, “%”, “vw”, “vh”]. You can restrict this to enforce consistent unit usage
  • settings.spacing.padding, Boolean. Controls whether the padding control appears for blocks
  • settings.spacing.margin, Boolean. Controls whether the margin control appears for blocks
  • settings.spacing.blockGap, Boolean or string. Set to true to enable the block gap control. The block gap controls space between blocks inside container blocks (Row, Stack, Group, Columns)
  • settings.spacing.customSpacingSize, Boolean. Set to false to prevent custom spacing values, forcing users to only use your defined scale

settings.layout

Layout settings define the content and wide-width dimensions that control how blocks flow within your page layouts. These are fundamental to block theme design.

  • settings.layout.contentSize, The default maximum width for content in a theme. This is the width of normal-aligned blocks. Typically set to your reading line length, 680px to 780px for text-heavy sites, wider for image-heavy layouts
  • settings.layout.wideSize, The maximum width for wide-aligned blocks. Wide alignment extends beyond contentSize but stays contained within the page layout. Typically 1200px to 1400px
  • settings.layout.allowEditing, Boolean. When true, users can change a block’s layout alignment in the editor

settings.border

Border settings control which border-related options appear in the editor and define any border presets.

  • settings.border.color, Boolean. Enables the border color picker
  • settings.border.radius, Boolean. Enables the border radius control
  • settings.border.style, Boolean. Enables the border style selector (solid, dashed, dotted)
  • settings.border.width, Boolean. Enables the border width control

settings.shadow

Shadow settings (introduced with expanded support in theme.json v3) let you define shadow presets that appear in the box shadow control for blocks that support it.

  • settings.shadow.presets, Array of shadow preset objects, each with name, slug, and shadow (a valid CSS box-shadow value)
  • settings.shadow.defaultPresets, Boolean. Set to false to remove WordPress’s built-in shadow presets

settings.blocks

The settings.blocks section is one of the most powerful and underused features of theme.json. It lets you override global settings on a per-block basis, giving specific blocks different color palettes, typography options, or spacing controls from the global defaults. Our dedicated guide on block settings in theme.json covers this in full detail.

"settings": {
  "blocks": {
    "core/button": {
      "color": {
        "palette": [
          { "name": "Primary", "slug": "primary", "color": "#0066cc" },
          { "name": "Secondary", "slug": "secondary", "color": "#444444" }
        ]
      },
      "typography": {
        "fontSizes": [
          { "name": "Small", "slug": "small", "size": "0.875rem" },
          { "name": "Medium", "slug": "medium", "size": "1rem" }
        ]
      }
    }
  }
}

The styles Object: Applying Styles to Elements and Blocks

Where settings define what exists in your design system, the styles object defines what is applied. Styles in theme.json are the default visual output, the CSS that WordPress generates from your declarations and applies to the front end and the editor simultaneously. This dual application (editor and front end get the same styles) is one of block themes’ key advantages over classic themes, where editor styles were often a separate and incomplete CSS file.

styles.color

Global color defaults applied to the entire site:

  • styles.color.background, The default page background color. Use a preset slug reference like "var:preset|color|white" or a direct CSS value
  • styles.color.text, The default body text color
  • styles.color.gradient, A default gradient background for the body

styles.typography

Global typography defaults:

  • styles.typography.fontFamily, The default font family for body text. Reference a preset slug or provide a CSS font-family value
  • styles.typography.fontSize, The default body font size
  • styles.typography.fontWeight, Default font weight for body text
  • styles.typography.lineHeight, Default line height for body text. 1.5 to 1.7 is typical for readable body copy
  • styles.typography.letterSpacing, Default letter spacing
  • styles.typography.textTransform, Default text transform
  • styles.typography.textDecoration, Default text decoration

styles.spacing

Global spacing defaults applied to the body:

  • styles.spacing.padding, Default padding for the body element. This controls the outer padding of the entire page, which is useful for adding consistent edge spacing on mobile
  • styles.spacing.margin, Default margin for the body element
  • styles.spacing.blockGap, The default gap between blocks in flow layout contexts

styles.elements

The styles.elements section is where you style HTML elements like headings, links, buttons, and form elements globally. This is how you set your H1 through H6 styles, your link color and hover state, and your button default appearance, all without writing a single line of CSS.

"styles": {
  "elements": {
    "h1": {
      "typography": {
        "fontFamily": "var:preset|typography|heading",
        "fontSize": "var:preset|font-size|xx-large",
        "fontWeight": "700",
        "lineHeight": "1.2"
      }
    },
    "h2": {
      "typography": {
        "fontFamily": "var:preset|typography|heading",
        "fontSize": "var:preset|font-size|x-large",
        "fontWeight": "700",
        "lineHeight": "1.3"
      }
    },
    "link": {
      "color": {
        "text": "var:preset|color|primary"
      },
      ":hover": {
        "color": {
          "text": "var:preset|color|primary-dark"
        },
        "typography": {
          "textDecoration": "underline"
        }
      }
    },
    "button": {
      "color": {
        "background": "var:preset|color|primary",
        "text": "var:preset|color|white"
      },
      "typography": {
        "fontWeight": "600",
        "fontSize": "var:preset|font-size|small"
      },
      "border": {
        "radius": "4px"
      },
      "spacing": {
        "padding": {
          "top": "0.75rem",
          "bottom": "0.75rem",
          "left": "1.5rem",
          "right": "1.5rem"
        }
      }
    }
  }
}

The elements you can target include: h1, h2, h3, h4, h5, h6, link, button, caption, cite. For interactive states, you can nest :hover, :focus, :active, and :visited inside element style objects.

styles.blocks

The styles.blocks section lets you apply default styles to specific block types. Every block in WordPress has a unique name (namespace/block-name), and you can target any of them here. This is how you set default styles for the Paragraph block, the Heading block, the Image block, the Group block, and so on.

"styles": {
  "blocks": {
    "core/paragraph": {
      "typography": {
        "fontSize": "var:preset|font-size|medium",
        "lineHeight": "1.7"
      }
    },
    "core/group": {
      "spacing": {
        "padding": {
          "top": "var:preset|spacing|50",
          "bottom": "var:preset|spacing|50"
        }
      }
    },
    "core/quote": {
      "border": {
        "left": {
          "color": "var:preset|color|primary",
          "style": "solid",
          "width": "4px"
        }
      },
      "spacing": {
        "padding": {
          "left": "var:preset|spacing|40"
        }
      }
    }
  }
}

CSS Custom Properties: How theme.json Becomes CSS

One of the most important things to understand about theme.json is how it compiles to CSS. WordPress reads your theme.json settings and generates CSS custom properties that are available globally on the front end and in the editor. Understanding the naming convention lets you use these variables in your custom CSS and even reference them in other theme.json values.

The naming convention follows this pattern:

  • Color presets: --wp--preset--color--{slug}, e.g., --wp--preset--color--primary
  • Font size presets: --wp--preset--font-size--{slug}, e.g., --wp--preset--font-size--large
  • Font family presets: --wp--preset--font-family--{slug}
  • Spacing presets: --wp--preset--spacing--{slug}, e.g., --wp--preset--spacing--40
  • Gradient presets: --wp--preset--gradient--{slug}
  • Shadow presets: --wp--preset--shadow--{slug}
  • Custom settings: --wp--custom--{path}, nested keys in a settings.custom object

When referencing presets within theme.json values, use the pipe-separated shorthand: "var:preset|color|primary". This compiles to var(--wp--preset--color--primary) in the generated CSS. In your custom stylesheet or per-block CSS, you can reference the full custom property directly.

Style Variations: Multiple Design Modes from One Theme

Theme.json supports style variations, alternate versions of your theme’s global styles that users can switch between in the Site Editor with a single click. Each variation is a separate JSON file stored in your theme’s styles/ directory. A variation file follows the same structure as theme.json but only needs to include the settings and styles that differ from the base theme. Everything not specified in the variation inherits from the base theme.json.

Style variations are powerful for themes that want to offer multiple visual modes, a light mode and a dark mode, a minimal layout and a bold layout, different color palettes for different industries. Our complete guide to style variations covers how to build, register, and maintain them effectively. For building a production-ready design system with design tokens that span across variations, the design system in theme.json guide is the natural next read.

Common theme.json Mistakes and How to Avoid Them

After working with theme.json across dozens of block theme projects, there are patterns of mistakes that appear consistently. Knowing them in advance saves significant debugging time.

  • Mixing preset references and direct values inconsistently: Some properties in styles accept preset slug references ("var:preset|color|primary"), while others accept direct CSS values (“1.5rem”). Mixing these inconsistently leads to confusing specificity and makes the design system harder to maintain. Decide on a convention and stick to it, always use preset references where available
  • Not setting defaultPalette and defaultGradients to false: If you have defined a custom color palette but have not disabled the WordPress default palette, users will see both palettes in the color picker, which is confusing and undermines your design system. Always set these to false when you have a complete custom palette
  • Forgetting that styles.blocks overrides affect the editor: Block styles defined in theme.json apply in both the editor and the front end. If you define a large padding on core/group, all Group blocks in the editor will have that padding by default. Design your styles with the editing experience in mind, not just the front end
  • Using pixel values for typography instead of rem or fluid: Hard-coded pixel values for font sizes do not respect user browser font size preferences and do not scale for accessibility. Use rem units for font sizes and enable fluid typography with clamp() for responsive scaling
  • Not specifying contentSize and wideSize: Without explicit layout size settings, block alignment behaves unpredictably. Always set these values early in your theme development process
  • Applying too many per-block style overrides: If you find yourself overriding styles for every block individually, your global styles are probably not set correctly. Fix the root cause in the global settings and styles rather than patching individual blocks

FAQ: theme.json Global Settings and Styles

Q: Can I use theme.json in a classic theme, or is it only for block themes?

A: Theme.json can be used in classic themes as well as block themes. Classic themes that include a theme.json file gain access to the global styles system and can define color palettes, font sizes, and spacing presets that appear in the block editor. However, classic themes do not get full Site Editor support, template editing, or the complete block theme architecture, theme.json in a classic theme only affects the block editor experience, not the template rendering system. If you are using theme.json in a classic theme as a transitional step toward block themes, it is a useful approach. For full block theme capabilities, you need a block theme.

Q: What is the difference between theme.json settings and styles?

A: Settings define what design tokens and editor controls exist, the palette of choices available. Styles define what is applied by default, the actual CSS values output to the page. A color defined in settings.color.palette exists as a CSS custom property and appears in color pickers, but it is not applied anywhere until you reference it in a styles property. Think of settings as your design vocabulary and styles as the default sentences you write with that vocabulary. Users can override your style defaults by changing block-level settings in the editor, but your settings define the available options.

Q: How do I add custom CSS properties to theme.json that are not part of the standard schema?

A: Use the settings.custom section. Any nested object you define there becomes a CSS custom property following the naming pattern --wp--custom--{key}--{subkey}. For example, if you define settings.custom.header.height as "80px", WordPress generates --wp--custom--header--height: 80px as a CSS custom property available globally. This is how you add design tokens that are not covered by the standard schema, animation durations, z-index values, maximum widths for non-layout contexts, custom border values, and similar design system tokens that do not fit the standard categories.

Putting It All Together: A Complete theme.json Example

A well-structured theme.json for a production block theme combines all of the sections covered in this guide into a coherent document. The order does not technically matter to WordPress, but following a consistent convention, schema, version, settings (color, typography, spacing, layout, border, shadow, blocks), styles (color, typography, spacing, elements, blocks), then customTemplates and templateParts, makes the file readable and maintainable.

Keep your theme.json in version control alongside your theme files. When you need to make global design changes, a brand color update, a typography scale adjustment, a new spacing preset, a single theme.json edit propagates the change across every block, every template, and every style variation that references the updated preset. This is the power of the declarative design system: one source of truth, applied everywhere consistently.

Theme.json is not just a configuration file, it is the specification of your site’s design language. Invest the time to understand each section thoroughly, and you will find that block theme development becomes faster, more predictable, and significantly more maintainable than anything that came before it in the WordPress ecosystem.

As a practical starting point, begin every new block theme project by defining your color palette, font families, and spacing scale in theme.json before writing any templates or patterns. Establishing these foundations first ensures that every block and template you create inherits from a coherent design system automatically. Refining theme.json as a living document throughout your project, adding presets as new design needs emerge, adjusting defaults based on real content testing, is the mark of a mature block theme development practice. The declarative approach rewards investment in the foundation more than any other aspect of WordPress theme development.