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 already defined 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. Style utilities can be combined and you can restrict style utilities to certain components. 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

How utilities work #

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 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 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; padding-right: 1em }
.align-right { text-align: right; padding-left: 1em }
.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 with the appropriate padding 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. In short, the following uses of utilities on a .box component are valid:

<div class="box"></div> <!-- no utility classes at all -->
<div class="box align-left red-text"></div>
<div class="box align-right red-text"></div>
<div class="box align-left red-text green-background"></div>
<div class="box align-right red-text green-background"></div>

.align-left cannot be combined with .align-right because the declarations of the text-align property contradict each other and both have the same importance. All possible utility combinations are computed by Warhol in advance and you will see a conflicting utilities debug message in your snapshot log if there are any conflicts.

It goes without saying that you do not have to use the same classes or class names in production as in the pattern library. Warhol only uses the class names to construct whitelists for its tests.

Known limitations #

Warhol is able to read utilities (and everything else) from any iframes it encounters, but properly merging utilities from different source pages (e.g. two different iframes) is currently not supported.

Tips for debugging #

  • Do not go crazy with utilities! They are tricky to get right and can have very far-reaching consequences. It is often 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.

Join our Slack Community

Any question not answered yet? You want to get the latest information on Warhol and discuss new features? Join our Slack Community.