With WordPress 6.9 just around the corner, it’s time to look at one of my favorite new theme developer tools: border radius size presets.
Added in Gutenberg 21.5, these size presets let you define an array of sizes that users can apply to blocks that support border radius. You can also reuse them within your own theme stylesheets and theme.json file.
Let’s take a dive into this new design tool.
Table of Contents
Defining radius size presets
Like other presets, you can define border radius sizes via the standard theme.json file in your theme. The new property can be defined via the settings.border.radiusSizes property (read the border documentation for theme.json for more information).
radiusSizes is an array of size objects, each accepting three properties:
name: A human-readable label for the size.slug: The machine-readable name for the size, which is used to generate a CSS custom property for the preset (e.g.,--wp--preset--border-radius--{slug}).size: The CSS value for the size.
Here is a simple example of a size named xs defined in theme.json:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"border": {
"radiusSizes": [
{
"name": "XS",
"slug": "xs",
"size": "0.125rem"
}
]
}
}
}
With the basics of how to define border radius size presets, let’s see what’s possible with the new feature.
Tip: I generally prefer a t-shirt naming convention when my radius presets scale from smaller sizes to larger.
Defining multiple presets
When building a theme, you most likely want to offer a range of standard size presets that match your theme’s design. For this tutorial, let’s assume you want seven sizes that scale from 0.125rem up to 1.5rem.
Use this code in your theme.json:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"border": {
"radius": true,
"radiusSizes": [
{
"name": "XS",
"slug": "xs",
"size": "0.125rem"
},
{
"name": "Small",
"slug": "sm",
"size": "0.25rem"
},
{
"name": "Medium",
"slug": "md",
"size": "0.375rem"
},
{
"name": "Large",
"slug": "lg",
"size": "0.5rem"
},
{
"name": "XL",
"slug": "xl",
"size": "0.75rem"
},
{
"name": "2XL",
"slug": "2-xl",
"size": "1rem"
},
{
"name": "3XL",
"slug": "3-xl",
"size": "1.5rem"
}
]
}
}
}
Note that the code also sets radius to true, which enables the border radius selector in the UI for blocks that support it.
To test your new sizes, add a Group, Cover, or some other block in the editor and look for the Styles Radius panel in the sidebar. Try moving the slider and seeing how the block reacts to the chosen size:

You can also unlink each of the corners and define individual radii for each. For example, the following screenshot shows selecting the 3-xl radius for the top right and bottom left corners but no radius for the top left and bottom right:

UI differences when defining many presets
It’s important to note that if you add more than seven presets, the range slider will change to a select dropdown in the UI.
If you want to give this a try, add the following full size to your existing radiusSizes array:
{
"name": "Full",
"slug": "full",
"size": "9999em"
}
Then refresh your editor and see the change:

Styling blocks with presets
Like all other presets that you can define via theme.json, WordPress automatically outputs these as CSS custom properties on the :root element. Here’s the CSS generated for the custom sizes you defined earlier:
:root {
--wp--preset--border-radius--xs: 0.125rem;
--wp--preset--border-radius--sm: 0.25rem;
--wp--preset--border-radius--md: 0.375rem;
--wp--preset--border-radius--lg: 0.5rem;
--wp--preset--border-radius--xl: 0.75rem;
--wp--preset--border-radius--2-xl: 1rem;
--wp--preset--border-radius--3-xl: 1.5rem;
}
This means that you can use these presets just like any other CSS custom property, accessing them via var(--wp--preset--border-radius--{slug}).
Let’s suppose you wanted Image blocks in your theme to have this design by default:

To do this, you would need to apply the radius to the Image block in your theme.json file under the styles property:
{
"styles": {
"blocks": {
"core/image": {
"border": {
"radius": {
"topLeft": "0px",
"topRight": "var(--wp--preset--border-radius--3-xl)",
"bottomLeft": "var(--wp--preset--border-radius--3-xl)",
"bottomRight": "0px"
}
}
}
}
}
}
To learn more about applying presets to blocks, check out the Using Presets documentation in the Theme Handbook.
Of course, you’re not limited to using presets in theme.json. You can apply them to global style variations, block style variations, and even use them directly in custom stylesheets.
Hand-drawn and other unique styles
As you read earlier, size presets are applied on individual corners of a block or element. For example, here is the HTML output when applying the 3xl size to a Group block:
<div class="wp-block-group" style="border-top-left-radius:var(--wp--preset--border-radius--3-xl);border-top-right-radius:var(--wp--preset--border-radius--3-xl);border-bottom-left-radius:var(--wp--preset--border-radius--3-xl);border-bottom-right-radius:var(--wp--preset--border-radius--3-xl)">
...
</div>
This means that when you register size presets, what you’re actually defining are values that can be applied to:
border-top-left-radiusborder-top-right-radiusborder-bottom-left-radiusborder-bottom-right-radius
For example, I really wanted to define a “hand drawn” size like this:
{
"name": "Hand Drawn",
"slug": "hand-drawn",
"size": "255px 15px 225px 15px/15px 225px 15px 255px"
}
This uses the two-value syntax that defines both the horizontal and vertical semi-major axes of the ellipse for each corner, but this form is meant to be used with the border-radius shorthand.
I’d hoped to allow users to pick a border radius and quickly get this result:

Such a preset doesn’t work because that value is only valid for the border-radius shorthand. Remember that sizes must be valid for individual corners.
Instead, I had to define the two separate presets that could be used individually on the corners.
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"border": {
"radius": true,
"radiusSizes": [
{
"name": "Drawn 1",
"slug": "drawn-1",
"size": "15px 255px"
},
{
"name": "Drawn 2",
"slug": "drawn-2",
"size": "255px 15px"
}
]
}
}
}
The two-value syntax (horizontal axis and vertical axis) is a valid value, so you can absolutely use it to accomplish some impressive designs.
The downside is that users must unlink the border radius control and define each of the corners to get that exact design for a block:

The upside is that they can try all sorts of neat combos of your registered radius size presets.
Of course, you can also make it easier for them by adding a “hand drawn” block style variation that automatically applies these radii.
Please share any unique border radius designs that you come up with.
Notable limitations
As I was testing this feature for the article, I ran into two notable limitations. They are not blockers for most use cases, but it’s worth knowing about them as you define your own border radius sizes.
Not all valid CSS values are allowed
I attempted to use calc(infinity * 1px) for the full size, but it didn’t work within the UI. Whenever selected, it applied the correct preset but the Default option was shown as selected in the UI.
Upon further testing, I attempted to use both var() and clamp() values, which also broke. As near as I can tell, this feature is limited to values without ( or ) characters, but it needs more investigation.
No way to disable custom radius sizes
Border radius presets are a nice start, but there is not currently a method of disabling the UI for custom sizes. Generally, other design tools will let you disable custom values via a customSettingName property.
You can set settings.border.radius to false in theme.json. That will disable presets and custom sizes from appearing in the UI.
There is an open ticket that discusses both this and the previous limitation in the Gutenberg repository.
Props to @welcher and @juanmaguitar for feedback and review on this article.
Leave a Reply