How to add hover and focus styles using theme.json

In the previous lesson you learnt how to use theme.json elements. In this lesson, I will show you examples of how to add hover and focus styles to link and buttons in theme.json.

This lesson has been updated in preparation for WordPress 6.3 with a planned release in August 2023.

Estimated reading time: 2 minutes

Last updated

Changes to the interface in WordPress 6.3

From WordPress 6.3, every block that supports link color has a setting with two tabs:
one for the default link state, and one for hover.

The link option is selected in the color panel, and a modal with two tabs is open: One tab with color swatches and a color picker for the default state, and one for hover.

There is no interface for the focus, active, or visited link states.
Button blocks do not support link color and as such, does not have a setting for hover styles yet.

How to add the CSS pseudo classes

From Gutenberg version 13.6 you can style :hover, :focus and :active states on link elements. From Gutenberg version 14.1 you can style outline and :visited.

The keys that you use to styles these states in theme.json are the same as the CSS pseudo classes:

  • styles.elements.link.:hover
  • styles.elements.link.:focus
  • styles.elements.link.:active
  • styles.elements.link.:visited

and styles.elements.link.outline

As with most theme.json settings, you can use this method to add site wide styles or style individual block types.

Examples

Lets continue with the some basic code examples that you can copy paste and adapt to match the design of your own full site editing theme.

Replacing site wide link underlines with a bottom border:

{
	"version": 2,
	"styles": {
		"elements": {
			"link": {
				"typography": {
					"textDecoration": "none"
				},
				"border": {
					"bottom": {
						"width": "2px",
						"color": "currentColor",
						"style": "solid"
					}
				},
				":hover": {
					"typography": {
						"textDecoration": "none"
					},
					"border": {
						"bottom": {
							"width": "2px",
							"color": "#111",
							"style": "dotted"
						}
					}
				}
			}
		}
	}
}

Adding a border around the site title block on :hover:

{
	"version": 2,
	"styles": {
		"blocks": {
			"core/site-title": {
				"elements": {
					"link": {
						"spacing": {
							"padding": ".5rem"
						},
						"typography": {
							"textDecoration": "none"
						},
						"border": {
							"width": "2px",
							"color": "transparent",
							"style": "solid"
						},
						":hover": {
							"typography": {
								"textDecoration": "none"
							},
							"border": {
								"width": "2px",
								"color": "#111",
								"style": "solid"
							}
						}
					}
				}
			}
		}
	}
}

Outline supports width, style, color and offset. Adjusting the focus outline on all button elements:

{
	"version": 2,
	"styles": {
		"elements": {
			"button": {
				":focus": {
					"outline": {
						"offset": "3px",
						"width": "3px",
						"style": "solid",
						"color": "blue"
					}
				}
			}
		}
	}
}

Please see the lesson about modifying block style variations if you want to edit the Outline style variation for the button block.

Styling the navigation block links is trickier.
You can choose to style the navigation block, or style the inner navigation link, page list, home link and submenu blocks individually.

This example is for the navigation block, and only works if the text decoration setting and the “Submenus: Open on click” settings are not used.

  • The text decoration setting adds a class name that increases the specificity, and the styles from theme.json are overriden.
  • The “Open on click” setting uses an HTML button element, and not a link.
{
	"version": 2,
	"styles": {
		"blocks": {
			"core/navigation": {
				"elements": {
					"link": {
						"typography": {
							"textDecoration": "none"
						},
						"border": {
							"bottom": {
								"width": "4px",
								"color": "transparent",
								"style": "solid"
							}
						},
						":hover": {
							"typography": {
								"textDecoration": "none"
							},
							"border": {
								"bottom": {
									"width": "4px",
								"color": "currentColor",
									"style": "solid"
								}
							}
						}
					}
				}
			}
		}
	}
}