Had a client call the other day, really happy with the new block theme we built. Said everything looked great… except the forms. The comment form, the little search bar in the header—they looked like they were styled in 2003. Total default browser look. He said, “It just feels… broken.” And he was right. For years, getting consistent form styling in WordPress has been a nightmare of CSS overrides and !important tags.
WordPress 6.9 is finally taking a real swing at this with `theme.json` form styling support. It’s not a home run yet, more like a solid double. But it’s a move in the right direction. We can now style some core form elements the *right* way, directly from the theme’s configuration file. As the official WordPress Developer Blog notes, this has been a long-requested feature.
The Old Way vs. The “Proper” Way
My first thought was, “Fine, I’ll just write some global CSS.” Slap some styles on input, select, and textarea in the theme’s style.css and call it a day. And yeah, that works. Until it doesn’t. You quickly find yourself in specificity wars with every single plugin that brings its own forms and stylesheets to the party. It’s a brittle, frustrating game of whack-a-mole.
The correct approach now is to define these styles in theme.json. This treats form elements as first-class citizens of the global styling system, just like buttons and headings. With the 6.9 update, we get two new elements to work with: select and textInput.
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"styles": {
"elements": {
"textInput": {
"border": {
"radius": "0.5rem",
"width": "1px"
},
"color": {
"background": "#f0f0f0"
},
"spacing": {
"padding": "0.75rem"
}
},
"select": {
"border": {
"radius": "0.5rem",
"width": "1px"
},
"color": {
"background": "#f0f0f0"
},
"spacing": {
"padding": "0.75rem"
}
}
}
}
}
So, What’s the Catch?
Here’s the kicker: this is only the first pass. It covers the basic text inputs and select dropdowns, but it leaves a few crucial things out. The biggest missing piece is pseudo-class support. You can’t style the :focus state in theme.json. Not yet, anyway. This is a big deal for accessibility and usability, as a clear focus indicator is essential.
So, for now, we’re in a hybrid world. You define the base styles in theme.json to keep things clean and integrated with the block theme system. Then, you supplement it with a small amount of CSS for the things that aren’t supported yet. Trust me on this, it’s better than going back to the old way of doing everything in a stylesheet.
- Use
theme.jsonfor: Background, border, padding, color—the foundational styles fortextInputandselect. - Use
style.cssfor: Focus states (:focus), styling labels, and handling unsupported input types like checkboxes or radios.
Look, this stuff gets complicated fast. If you’re tired of debugging someone else’s mess and just want your site to work, drop my team a line. We’ve probably seen it before.
It’s a step forward, and a welcome one. It makes themes cleaner and more maintainable. Is it perfect? No. But it’s a start. What other elements do you think need theme.json support next?
Leave a Reply