Style utilities are general-purpose helpers for your components. Classes like .align-right or .large-shadow are examples of such style utilities. From Warhol's perspective the use of style utilities on components appears as unexpected CSS declaration error... unless you configure style utilities in the utils section in your configuration! Warhol can then build a list of styles that components can have in addition to their component styles without causing error messages.

By declaring style utilities to Warhol you quite literally create a whitelist of sets of styles that will not trigger unexpected CSS declaration errors. You do not need to care about style utilities if only use Warhol for theme checking.

Example configuration #

  "patternLibUrl": "https://warhol.io/components",
  "utils": {
    "utilsUrl": "https://warhol.io/components/utils",
    "sources": [
      { "type": "rule", "selector": ".align-left", "components": [ ".image", ".box" ] },
      { "type": "rule", "selector": ".align-right", "components": [ ".image", ".box" ] ] },
      { "type": "element", "selector": ".shadow", "name": "Shadow utility" }

Field utils.utilsUrl (optional, string, defaults to the pattern lib URL) #

If your utilities live on a specific URL in your pattern library, you can specify this here. If you omit utils.utilsUrl, the top top-level patternLibUrl will be used. If you set neither the utils.utilsUrl nor the top top-level patternLibUrl, you will get an error.

Field utils.sources (required, array of objects) #

Sources for utilities. Each utility is described by an object:

  • type (either "rule" or "element"): whether to read the utility styles from an element or from a CSS rule
  • selector (string, required, non-empty): the selector for the style utility
  • components (list of string, optional): target selectors for the components that can use this utility. By default all utilities can be used by all components. Use this field to restrict utilities to specific components.
  • name (string, optional, non-empty, defaults to null): utility name defaults to null

The distinction between type="element" and type="rule" is very important! The former will read styles from an element in a web page (just like with virtually everything else in Warhol) while the latter will take styles directly from matching rules in your style sheets! This has the huge advantage that this allows for very precise style selection as only the styles from the matching CSS rules end up defining the utility.

With type="element" you have to make sure that only the styles for your utility apply to the source element, which may be almost impossible! If any style sheet in the pattern library uses the * selector to set any styles, these styles will also appear in your utilities. You probably do not want this to happen!

The primary disadvantage of type="rule" is that it ties Warhol directly to implementation details of your pattern library. With type="rule", Warhol will search all style sheets used in the pattern library for rules that uses one of the exact selectors given in selector. The CSS from the resulting rules are then applied to a dummy element and the resulting styles are captured for the utility. This is quite a delicate process! Be very sure to check the snapshot error log in the browser extension or Warhol's web app to make sure that Warhol was able to find a source rule for each utility in your configuration!

Another potential problem of type="rule" is related to the way the resulting utility is constructed. When the utility's styles are built from a dummy element, only CSS variables that were defined on the root element (usually <html>) or on <body> can have any effect on the resulting utility.

Note that the rules or classes used to define style utilities only need to exist in your pattern library. They are only used to build a whitelist of styles and Warhol does not need to know anything about their counterparts in your production web site.

If a selector matches more than one element or appears as the selector in more than one CSS rule, the styles from all matching sources will be combined into a single style utility. You can use this to compose utilities. Given the following CSS...

.align-left { text-align: left }
.align-right { text-align: left }
.red-text { color: red }
.green-background { background-color: green }

... and the following Warhol configuration...

  "patternLibUrl": "https://warhol.io/components",
  "utils": {
    "sources": [
      { "type": "rule", "selector": ".align-left, .red-text", "components": ".box" },
      { "type": "rule", "selector": ".align-right, .red-text", "components": ".box" },
      { "type": "rule", "selector": ".green-background" }

... this configuration defines three utilities, each composed of the styles defined in rules, not elements. The resulting utilities allow .box components to be aligned on the left or the right if their text is also red. They, along with all other components can also have green as a background color, because the third utility is not restricted to any particular component.

Tips for debugging #

  • Do not go crazy with utilities! They are tricky to get right and can have extremely far-reaching consequences. It is almost always better (and simpler and, for the human consumers of your pattern library, much more clear and intuitive) to define a few extra component variants.
  • Check the snapshot error log in the web app to make sure that Warhol was able to find source rules and/or elements for each utility
  • Inspect your style utilities in the browser extension or the web app to make sure that the utilities do not contain to many or to few styles