Create utilities
Style utilities are general-purpose helpers for
your components. If you ever need to slap a
box-shadow
on an existing component, style utilities are what you need to stop
Warhol from complaining about unexpected styles the component in question has. If we
just re-use the pattern library from before
and add a shadow to a button component in production,
the result is predictable:
The error message's description is not wrong, but what if we want to be able to add a shadow to a button or any other component?
How utilities work #
Style utilities enable us to essentially whitelist certain modifications to the styles of select components, which will stop Warhol from reporting things like additional shadows or adjusted text alignment as errors.
Warhol can read style utilities from your pattern library like it can read the color palette and component styles. Utilities are somewhat special in that you will probably want to be sure that you only whitelist precisely the properties that you have in mind for your utility. There are two style utility sources that Warhol can use:
- An element in your pattern library, which must only contain the styles that you want to use in your utility. When you use elements as utility sources you must be absolutely certain that only these styles apply to the element.
- A CSS rule from for pattern library that sets the styles that you want to use in your utility. Compared to elements, it's easier to pick only the right styles for a utility but it makes Warhol depend on some implementation detail of your pattern library.
Utilities are finicky and you should probably read the more detailed explanation in the configuration documentation before you use utilities in your production project. For now, let's power right ahead. Just remember:
- Utilities are whitelists for style errors on components
- Utilities only work on components (not on children or non-components)
- Elements and CSS rules can serve as sources for utilities
Now let's fix our shadow problem!
Adding utilities #
A shadow utility is a great candidate for a utility that we can source from an element. Just add the following to the pattern library:
<div class="shadow-util" style="box-shadow: black 0 0 1em;">
<p>Placeholder text for box-shadow</p>
</div>
Our pattern library is slowly getting more and more complex, but we can still
be sure that only the box-shadow
property applies to the div
with the class
shadow-util
. Now we only need to point Warhol to just this div
and configure
this as a utility source. Let's go to the web app, open up the pattern library
configuration and replace null
in the “Utils” field with the following:
{
"sources": [
{
"type": "element",
"selector": ".shadow-util",
"name": "Shadow utility"
}
]
}
This is probably pretty self-explanatory for you at this point. As usual, the
name
field is optional and defaults to the selector. When we save the pattern
library configuration, re-generate the snapshots and re-download the snapshots
into the browser extension, we can see the utility listed in the
patterns tab in the devtools panel:
As for the tests, well …
To be positive: the component's name “Basic button + Shadow utility” tells
us that Warhol has managed to read and apply the utility styles to the
component. Warhol has also stopped complaining about the unexpected CSS
declarations and instead now mopes about the shadow color not conforming to the
theme. And that's not wrong: there is, after all, no black
allowed in our
color palette. Every color that you use on a page must be a theme color, down to
the last shadow's alpha component. Updating this example's pattern library to
make the production page pass without any error is left as a (very trivial)
exercise for the reader.
Element utilities vs. rule utilities #
If your pattern library is more complex than our simple example, creating isolated examples for utilities may not be easy. Global styles can make it next to impossible to create elements that contain nothing but the utility styles and such elements, if possible, may be not of much use to your pattern library's human users. Rule utilities are an alternative way to define utilities that have different trade-offs from element utilities and may be a better fit for what you try to accomplish.
With rule utilities, you do not need to build an example element. Instead you
just specify selectors for CSS rules and Warhol builds the example element
automatically. For each rule utility, Warhol creates a <div>
element in an
isolated sandbox, applies the CSS declarations from the rule utility's to the
element's inline styles and then records the element's styles just like an
element utility. This isolates the CSS in question from any global styles that
may interfere, but also ties your utility to an implementation detail of your
pattern library.
For our shadow utility, as long as we have some style sheet in our pattern library that contains a rule like this …
.shadow {
box-shadow: black 0 0 1em;
}
… and we update the type
field in the utility configuration …
{
"sources": [
{
"type": "rule",
"selector": ".shadow",
"name": "Shadow utility"
}
]
}
… we get back an equivalent utility from before, just defined and built in a slightly different way.
Key takeaways #
- Use utilities to allow well-defined deviations from a component's usual styles
- 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.