Update March 2023 - the latest releases in Webflow mean we can now use custom HTML attributes to make modifications to components (formerly 'symbols') more easily, without the need for either :has() or a hidden link!

Like a lot of web folks, I'm very excited about the upcoming :has() selector and all the opportunities it'll bring.

One thing it'll let us do is modify the style of symbols in Webflow using override fields.

Background

Currently the only override fields we can set on symbols are text, rich text, images, links and videos. There's no styling options for colours or so forth (although there have been hints this may come at some point).

So, to change the styling of a symbol, we either have to resort to JS (here's a link to a cloneable which does this), or make different versions of our symbols - which isn't really much of a solution.

Enter the :has() selector!

Using :has() with attribute selectors

The :has() selector lets us target elements based on their descendents or siblings.

So if we set an attribute of an element inside a symbol using an override field, we can then target and modify the styling of the parent symbol - plus any other elements within the symbol.

Let's assume we've got a symbol for a hero block, with class .hero, and we want to make a dark version of this hero.

A symbol in both light and dark styles
  1. We create a hidden link element in the symbol and give a class .style-link.
  2. We create an override link field on the symbol (let's call the field Style) and connect the hidden link element to this field.
  3. We override this Style link field with a URL that contains a defined string, for example "style-dark".
  4. We then add an embed element onto the page with some custom CSS:
<style>  
.hero:has(.style-link[href*=“style-dark”]) h1
{
color: white;
}
.hero:has(.style-link[href*=“style-dark”]) p {
color: white;
}
.hero:has(.style-link[href*=“style-dark”]) {
background-color: black;
}
.hero:has(.style-link[href*=“style-dark”]) .btn-primary {
background-color: white;
color: black;
}
.hero:has(.style-link[href*=“style-dark”]) .hero-wrapper {
flex-direction: row-reverse;
}
</style>

So in each case, we're targeting .hero elements that are ancestors to a .style-link with an href that contains the string "style-dark".

We're then styling different elements within this symbol (like headings, paragraph text etc).

We can even make more substantial layout changes like reversing a flex row (or changing grid layouts) - see the final CSS rule.

To make it slightly easier to choose an style from a defined list, we can create a number of empty pages on your Webflow site, and use the Style link field to select one of these. For example we can create pages called "Style Light" and "Style Dark" - just remember that the slugs for these pages need to match the href we're looking for.

Here's a link to a cloneable demonstrating this approach.

The catch... :has() support is limited... for now!

Unfortunately :has() is only supported on Safari at the moment, so this isn't a workable solution on live sites just yet.

There is support for it on Chrome Beta though, so if you're a Chrome user you can play around with this now!