How to Add Custom Fonts to Block Themes Without Plugins in 2026

Why Custom Fonts Matter for Block Themes

Typography is one of the most impactful design decisions you can make for any website. According to a study by MIT’s Agelab, well-chosen fonts can improve readability by up to 20% and increase user trust significantly. For WordPress block themes, the good news is that you no longer need a plugin to add custom fonts, the native theme.json system handles everything out of the box.

Since WordPress 6.0, the fontFace property in theme.json has provided a clean, standards-based way to register and self-host custom fonts. This approach offers several advantages over plugin-based solutions: zero additional HTTP requests to plugin assets, full GDPR compliance through local hosting, complete integration with the Site Editor’s typography controls, and no dependency on third-party plugin maintenance.

In this comprehensive guide, you will learn how to add custom fonts to your WordPress block theme using only theme.json, no plugins required. We will cover everything from basic font registration to variable fonts, fluid typography, style variations, and performance optimization. Whether you are building a new block theme from scratch or customizing an existing one, this guide has you covered. For a broader setup perspective, also see our block theme development workflow guide.

Understanding the Block Theme Font System

Before diving into the code, it helps to understand how WordPress handles fonts in block themes. The entire system revolves around theme.json, which is the central configuration file for block theme settings and styles.

How theme.json Font Registration Works

When you define a font in theme.json, WordPress does several things automatically:

  • Generates @font-face CSS rules, WordPress reads your fontFace declarations and outputs the correct @font-face CSS in the document head. No need to write CSS manually.
  • Creates CSS custom properties, Each font family gets a CSS variable like --wp--preset--font-family--your-slug that you can reference anywhere in your theme.
  • Registers fonts in the Site Editor, Your custom fonts automatically appear in the typography panel of the WordPress Site Editor, making them available to content creators.
  • Handles font file loading, When using local font files with the file:./ prefix, WordPress resolves the path relative to your theme directory.

Local Fonts vs. CDN-hosted Fonts

There are two approaches to serving custom fonts in a block theme:

Local self-hosting (recommended): Font files (.woff2) live inside your theme directory. This is the preferred approach because it ensures GDPR compliance (no data sent to Google), eliminates external dependencies, allows offline development, and gives you full control over caching headers.

CDN-hosted (Google Fonts, Adobe Fonts): Fonts are loaded from an external server. This still works but requires an additional HTTP connection, sends visitor IP addresses to the font provider (a GDPR concern in Europe), and adds a dependency on external infrastructure availability.

In January 2022, a German court ruled that loading Google Fonts from Google’s CDN violates GDPR because it transmits visitor IP addresses without consent. Since then, self-hosting fonts has become the industry standard for European websites and many international projects.

Step 1: Prepare Your Font Files

Choosing the Right Format

For modern block themes, WOFF2 is the only format you need. It has 97%+ browser support globally (according to Can I Use), offers 30% better compression than WOFF, and is the format WordPress core itself uses for bundled fonts.

You do not need to include WOFF, TTF, or EOT files. Those formats were necessary for legacy browsers (IE11 and below) that block themes do not support anyway.

Where to Get Fonts

Several legitimate sources provide fonts suitable for self-hosting:

  • Google Fonts, Over 1,500 free, open-source font families. Download the font family and convert to WOFF2.
  • google-webfonts-helper, A community tool that lets you download Google Fonts directly in WOFF2 format with the correct CSS snippets.
  • Font Squirrel, Free fonts with a generator that converts any font to web formats.
  • Adobe Fonts, Included with Creative Cloud subscriptions. Some fonts allow self-hosting.

Organizing Font Files in Your Theme

Create a clean directory structure inside your block theme. The convention used by WordPress core themes (Twenty Twenty-Four, Twenty Twenty-Five) is to place fonts under assets/fonts/:

your-theme/
├── assets/
│   └── fonts/
│       ├── inter/
│       │   ├── Inter-Regular.woff2
│       │   └── Inter-Bold.woff2
│       └── playfair-display/
│           ├── PlayfairDisplay-Regular.woff2
│           ├── PlayfairDisplay-Italic.woff2
│           ├── PlayfairDisplay-Bold.woff2
│           └── PlayfairDisplay-BoldItalic.woff2
├── style.css
└── theme.json

Here is a helper script that sets up this directory structure and explains how to download fonts:

Step 2: Register Fonts in theme.json

Basic Font Family Registration

The core of adding custom fonts is the settings.typography.fontFamilies array in your theme.json. Each entry defines a font family with one or more fontFace declarations.

Here is how to register a basic font family with regular and bold weights:

Let us break down what each property does:

  • fontFamily, The CSS font-family value, including fallback. This is what gets used in stylesheets.
  • name, The human-readable label shown in the Site Editor’s typography panel.
  • slug, Used to generate the CSS custom property: --wp--preset--font-family--inter.
  • fontFace, An array of font face declarations, similar to CSS @font-face rules.
  • fontDisplay: swap, Tells the browser to show fallback text immediately, then swap in the custom font once loaded. This prevents the Flash of Invisible Text (FOIT).
  • src, The path to the font file. The file:./ prefix resolves to your theme root directory.

Adding Multiple Weights and Styles

Most professional designs require more than just regular and bold. Here is how to register a font with regular, italic, bold, and bold-italic variants:

Each font face declaration targets a specific weight and style combination. When you use font-weight: 700 and font-style: italic together in your CSS, the browser knows exactly which font file to load, PlayfairDisplay-BoldItalic.woff2 in this case.

Important: Only include the weights and styles you actually use. Each font file adds to the page weight. A typical body font needs regular (400) and bold (700) at minimum. Add italic variants only if your content uses them. Medium (500) and semibold (600) are nice to have for UI elements like buttons and navigation.

Step 3: Use Variable Fonts for Maximum Flexibility

Variable fonts are a modern font technology where a single file contains an entire range of weights (and sometimes widths and other axes). Instead of loading separate files for regular, medium, semibold, and bold, one variable font file covers all of them.

Benefits of Variable Fonts

  • Smaller total file size, One variable font file (typically 100-200KB) replaces 4-8 static files (50-80KB each).
  • Unlimited weight choices, Use any weight between the range (e.g., font-weight: 450) instead of being limited to predefined values.
  • Smoother animations, You can animate font-weight smoothly in CSS transitions.
  • Browser support, 95%+ global support according to Can I Use.

Here is how to register a variable font in theme.json:

The key difference is the fontWeight value. Instead of a single number like "400", you specify a range like "100 900". WordPress recognizes this as a variable font and generates the correct CSS.

Google Fonts labels variable fonts clearly on their website. Look for the “Variable” badge next to the font name. When downloading, select the variable font option specifically, it will typically be named something like Inter-VariableFont_slnt,wght.woff2.

Step 4: Apply Fonts to Your Theme Elements

Registering fonts makes them available. Now you need to apply them to specific elements throughout your theme. This is done in the styles section of theme.json.

Global Typography and Element Styles

The styles section lets you set a default body font, heading fonts, and element-specific typography:

The font pairing shown above, Inter for body text and Playfair Display for headings, is a classic combination of a clean sans-serif with an elegant serif. This pairing works because the contrast between the two fonts creates visual hierarchy without clashing.

A few popular font pairings that work well for block themes:

  • Inter + Playfair Display, Clean modern body with elegant serif headings. Great for blogs, magazines, and editorial sites.
  • DM Sans + DM Serif Display, Designed to work together from the same foundry. Perfect harmony.
  • Source Sans 3 + Source Serif 4, Adobe’s open-source pair. Excellent for documentation and long-form content.
  • Outfit + Fraunces, Contemporary geometric sans with a quirky variable serif. Great for creative portfolios.
  • Geist + Geist Mono, Vercel’s clean modern fonts. Perfect for developer and tech-focused sites.

Block-Level Typography Overrides

Beyond global elements, you can target specific WordPress blocks. This is powerful for creating distinct typography for quotes, code blocks, navigation, and other components:

Block-level overrides are one of the most powerful features of the block theme font system. You can give every block its own typographic personality while maintaining overall design coherence. The Site Editor respects all of these settings and shows the correct fonts in the visual editor.

Step 5: Implement Fluid Typography

Fluid typography automatically scales font sizes between a minimum and maximum based on the viewport width. Instead of using media queries to change font sizes at breakpoints, the font size smoothly transitions across all screen sizes.

WordPress 6.1 introduced built-in fluid typography support in theme.json. Here is how to configure it:

When fluid is set to true at the settings level, WordPress generates clamp() CSS functions for each font size. For example, the “Large” size becomes something like clamp(1.25rem, 1.25rem + ((1vw - 0.48rem) * 0.962), 1.75rem).

This means your headings will be appropriately large on desktop screens but automatically shrink to comfortable sizes on mobile, without a single media query. The fluid values ensure that text remains readable on every device width between mobile and desktop.

Best Practices for Fluid Font Sizes

  • Keep body text ranges tight, Body text should not vary much between mobile and desktop. A range of 0.95rem to 1.1rem works well.
  • Let headings scale more dramatically, Large headings can scale from 1.75rem on mobile to 4rem on desktop.
  • Test on real devices, Fluid typography looks different on actual phones versus browser DevTools. Test on real hardware when possible.
  • Do not forget line-height, As fonts scale, line-height should adjust proportionally. Use unitless values (like 1.6) which scale with the font size.

Step 6: Create Style Variations with Different Font Pairings

One of the best features of block themes is style variations, alternative design presets that users can switch between in the Site Editor. You can create style variations that offer different font pairings while keeping everything else the same.

Style variations are JSON files placed in the styles/ directory of your theme. Each file can override any setting from the main theme.json.

Here is an example style variation that swaps the default sans-serif/serif pairing for an all-serif design:

Save this file as styles/elegant-serif.json in your theme. Users will then see an “Elegant Serif” option in the Site Editor under Styles → Browse Styles.

The key to good style variations is using generic slugs like body-font and heading-font instead of font-specific slugs. This way, when a style variation replaces the font family definitions, all the CSS custom properties automatically update throughout the theme.

WordPress core themes like Twenty Twenty-Five ship with multiple style variations, each featuring different font pairings. This pattern gives users design flexibility without requiring any custom code or plugin.

Google Fonts via CDN (Alternative Approach)

While self-hosting is strongly recommended, there are situations where loading fonts from Google’s CDN makes sense, rapid prototyping, themes targeting non-European audiences, or when you need quick access to the full 1,500+ font library without downloading files.

This approach uses functions.php to enqueue the fonts rather than theme.json:

After enqueuing, you still reference the fonts in theme.json by defining the font families, just without the fontFace property since the CSS is loaded externally:

{
  "fontFamily": "\"Inter\", sans-serif",
  "name": "Inter",
  "slug": "inter"
}

Remember: This approach sends visitor data to Google. If your site serves European visitors, you need explicit consent or should use the local self-hosting approach described in Steps 1-2.

Performance Optimization

Custom fonts can impact page load performance if not optimized properly. Here are the key strategies to ensure your fonts load fast without blocking rendering.

Font Preloading

For fonts used above the fold (body text, main headings), preloading tells the browser to start downloading them immediately, before it even discovers them in CSS. This can reduce the Flash of Unstyled Text (FOUT) significantly:

Preload only 1-2 critical fonts. Preloading too many fonts wastes bandwidth because the browser downloads them all at the highest priority, competing with other critical resources like CSS and JavaScript.

Font Subsetting

If you only need Latin characters, you can subset your fonts to remove Cyrillic, Greek, Vietnamese, and other character sets. Tools like glyphhanger (by Zach Leatherman of Eleventy) and pyftsubset can reduce font file sizes by 40-60%.

For example, a full Inter Regular file might be 97KB, but the Latin-only subset could be just 40KB. Multiply that saving across 4-6 font files and you have saved several hundred kilobytes.

Performance Checklist

  • Use WOFF2 format exclusively (best compression)
  • Set fontDisplay: swap in all fontFace declarations
  • Preload only 1-2 critical font files
  • Subset fonts to only the character sets you need
  • Use variable fonts to reduce total file count
  • Keep total font payload under 200KB
  • Self-host fonts to avoid external connection overhead
  • Test with Google PageSpeed Insights and check the “Ensure text remains visible during webfont load” audit

Troubleshooting Common Issues

Fonts Not Showing in the Site Editor

The most common cause is a JSON syntax error in theme.json. Even a single misplaced comma will silently break the entire file. Validate your JSON with a tool like JSONLint before testing.

Also verify that your font file paths are correct. The file:./ prefix resolves relative to the theme root. If your font is at your-theme/assets/fonts/inter/Inter-Regular.woff2, the src should be file:./assets/fonts/inter/Inter-Regular.woff2.

Font Loads on Frontend but Not in Editor

This happens when you enqueue fonts via functions.php but only for the wp_enqueue_scripts hook. The block editor uses a different hook, enqueue_block_editor_assets. If using the CDN approach, make sure to enqueue for both hooks.

The theme.json approach avoids this entirely because WordPress automatically loads fonts in both the editor and the frontend.

Flash of Unstyled Text (FOUT)

A brief flash of the fallback font before the custom font loads is normal behavior with fontDisplay: swap. To minimize it:

Variable Font Weight Not Working

If specific weights of your variable font are not rendering correctly, check that you specified the weight range correctly in theme.json. It should be a space-separated string like "100 900", not a comma-separated value. Also verify that you downloaded the actual variable font file, not just a static weight extracted from the variable family.

WordPress Font Library: The Built-in Font Manager

WordPress 6.5 introduced the Font Library, accessible from the Site Editor under Styles → Typography → Manage Fonts. This feature provides a visual interface for installing and managing fonts, including uploading custom font files and installing Google Fonts directly from the admin.

The Font Library stores user-installed fonts in wp-content/fonts/, separate from theme fonts. This means fonts installed through the Font Library persist even when you switch themes.

For theme developers, the theme.json approach is still the correct way to bundle fonts with your theme, the Font Library is primarily a user-facing feature for site customization. However, understanding both systems helps you make informed decisions about where fonts should live in your project.

Real-World Font Pairing Examples

Here are five proven font combinations from popular block themes, along with the design rationale behind each pairing:

1. Corporate / Business

Headings: Outfit (geometric sans-serif) | Body: Source Serif 4

The geometric precision of Outfit conveys professionalism, while Source Serif’s readability makes long-form content comfortable. Used by agency and SaaS themes.

2. Editorial / Magazine

Headings: Playfair Display (high-contrast serif) | Body: Lato

Playfair’s dramatic thick-thin contrast commands attention in headlines. Lato’s friendly geometry provides an excellent reading experience for articles.

3. Creative / Portfolio

Headings: Space Grotesk (quirky sans-serif) | Body: General Sans

Space Grotesk’s slightly unconventional letterforms add personality. General Sans keeps body text professional without being boring.

4. Developer / Documentation

Headings: Geist (Vercel’s sans-serif) | Body: Inter | Code: JetBrains Mono

Three fonts that each excel in their role. Geist is clean and technical, Inter is the gold standard for UI text, and JetBrains Mono is purpose-built for code readability.

5. Elegant / Luxury

Headings: Cormorant Garamond (refined serif) | Body: Lora

Both are serifs, but they work because Cormorant Garamond is display-oriented (for large sizes) while Lora is text-oriented (for body sizes). The shared serif DNA creates cohesion.

Summary and Next Steps

Adding custom fonts to a WordPress block theme is a native capability that requires no plugins. The entire workflow fits within theme.json:

  1. Prepare font files, Download WOFF2 files and organize them in assets/fonts/
  2. Register in theme.json, Define fontFamilies with fontFace declarations
  3. Apply to elements, Use the styles section to set fonts for body, headings, and specific blocks
  4. Add fluid sizing, Enable fluid typography for responsive font sizes
  5. Create style variations, Offer users alternative font pairings
  6. Optimize performance, Preload critical fonts and subset when possible

This approach is future-proof, performant, and fully integrated with the WordPress Site Editor. As the block theme ecosystem continues to mature, the theme.json typography system will only become more powerful, making it the right foundation for any custom font implementation. To fine-tune how block settings work alongside fonts, read our guide on defining block settings in theme.json.

For deeper reference, explore the official WordPress typography documentation and study how core themes like Twenty Twenty-Five implement their font systems.

Scroll to Top