Variable fonts let you use every weight of a typeface with a single font file. Instead of loading separate files for regular, medium, semibold and bold, your theme loads one file and can use any weight in between – 450 is just as valid as 400 or 500. In this tutorial, we’re going to take a look at how you can add a variable font to your block theme with theme.json.
Registering a variable font works the same way as registering a static font, with one difference: the fontWeight value is a range instead of a single number. We’ll use the geometric sans-serif DM Sans, a free variable font with weights from 100 to 1000. I’ve used it in my block theme Tove, among other places.
Variable fonts can be good for performance too, since one file means one request instead of several. They’re not always smaller, though. In Tove, the variable files cover every weight from 100 to 1000, but they’re 12 KB larger than the four static files they replaced. If your theme only uses one or two weights, static files can be the lighter (but less flexible) choice.
Getting the font file
Let’s start by downloading DM Sans from Google Fonts. The ZIP file includes a static folder with one file per weight, but we can ignore that. The file we’re looking for is the variable one at the top level, named something like DMSans-VariableFont_opsz,wght.ttf.
TTF files work in browsers, but WOFF2 files are compressed and usually much smaller, so let’s convert it with fontTools, a free Python tool:
pip install fonttools brotlifonttools ttLib.woff2 compress -o dm-sans-variable.woff2 "DMSans-VariableFont_opsz,wght.ttf"
Next, put the WOFF2 file in your theme, for example in assets/fonts/. If you plan to submit the theme to WordPress.org, check that the font’s license is GPL-compatible, include a copy of the license with the theme, and mention the font and its license in the readme. DM Sans uses the SIL Open Font License, like most fonts on Google Fonts, which means it’s good to go on WordPress.org. Check the license for other fonts, though.
Registering the font in theme.json
You’ll find theme.json in the root folder of your theme. It’s where most of a block theme’s style and layout settings live. Open it in a code editor, either on your computer or over SFTP on your server. If you’re working on a theme you didn’t build yourself, make the changes in a child theme instead. Otherwise, they might be overwritten the next time you install an update to the theme, and speaking as someone who receives a lot of support requests from people who have done that, it’s best avoided.
Now we can add the font to settings.typography.fontFamilies in theme.json. The fontFace array tells WordPress where the file is and which weights it covers:
{ "$schema": "https://schemas.wp.org/trunk/theme.json", "version": 3, "settings": { "typography": { "fontFamilies": [ { "name": "DM Sans", "slug": "dm-sans", "fontFamily": "\"DM Sans\", sans-serif", "fontFace": [ { "fontFamily": "DM Sans", "fontStyle": "normal", "fontWeight": "100 1000", "src": [ "file:./assets/fonts/dm-sans-variable.woff2" ] } ] } ] } }}
The important line for our variable font is "fontWeight": "100 1000". Two numbers separated by a space tell the browser that this one file covers every weight from 100 to 1000. With a static font, we’d add one fontFace entry per file instead, each with a single weight like "400".
Make sure the range matches the font. You’ll usually find it on the font’s Google Fonts page.
The file:./ prefix makes the path relative to the theme folder. WordPress takes care of outputting the @font-face CSS, both on the front end and in the editor.
Using the font in your styles
Registering the font makes it available in the editor’s typography settings. To make it the default, let’s set it in styles, at the top level of theme.json next to settings, using the CSS variable WordPress creates from the slug. You can also do this in the Site Editor directly: go to “Appearance” → “Editor” → “Styles” → “Typography”, select “Text” or “Headings”, and pick DM Sans from the font list.
"styles": { "typography": { "fontFamily": "var(--wp--preset--font-family--dm-sans)", "fontWeight": "450" }, "elements": { "heading": { "typography": { "fontWeight": "650" } } }}
This is where the variable font pays off. Any weight inside the range works, so we can use in-between values like 450 or 650 to fine-tune the typography, without loading another file.
Adding italics
Many variable fonts come with a separate italic file, like DMSans-Italic-VariableFont_opsz,wght.ttf. Let’s convert it the same way, and add a second entry to the fontFace array with "fontStyle": "italic". With both styles, the font family entry in settings.typography.fontFamilies looks like this:
{ "name": "DM Sans", "slug": "dm-sans", "fontFamily": "\"DM Sans\", sans-serif", "fontFace": [ { "fontFamily": "DM Sans", "fontStyle": "normal", "fontWeight": "100 1000", "src": [ "file:./assets/fonts/dm-sans-variable.woff2" ] }, { "fontFamily": "DM Sans", "fontStyle": "italic", "fontWeight": "100 1000", "src": [ "file:./assets/fonts/dm-sans-variable-italic.woff2" ] } ]}
Please don’t skip this step. Without an italic file, browsers fake the italics by slanting the regular letters, which is an eyesore. You can turn that off with CSS, as I describe in How to disable faux weights with CSS and font synthesis. The italic file is only downloaded when a page actually uses italic text, so there’s no downside in including one.
That’s it!
A note on replacing fonts in existing themes
If you’re switching an existing theme from static font files to a variable font, be careful about deleting the old files. I ran into this when I updated Tove: when someone customizes fonts in the Site Editor, their saved Global Styles can include a copy of the theme’s font definitions, file paths and all. If those files disappear, their site falls back to a system font, and you won’t see it in your own testing unless you’ve customized the fonts yourself.
The safe option is to keep the old files in the theme after you switch, so existing sites keep working. They’ll only be loaded if they’re still in use.


