Warhol

Components


Components are re-useable building blocks for web applications with a canoical implementation in both HTML and CSS. While themes make sure that all of your elements conforn to a few general guidelines regarding colors and typography, components must implement the exact styles prescribed in the pattern library and can only have child elements with the exact styles prescribed in the pattern library.

Components through Warhol's eyes

Consider the following example component definiton:

<!-- "Icon button" component defined in pattern library -->

<button class="iconButton">
  <span class="iconButton__icon">
    <img class="iconButton__icon__image" src="checkmark.png" />
  </span>
  <span class="iconButton__text">OK</span>
</button>

<style>
.iconButton {
  width: 200px;
  padding: 0.5em;
  position: relative;
}
.iconButton::after { /* add a two-tone underline */
  content: "";
  position: absolute;
  bottom: 0.25em;
  left: 0.5em;
  width: calc(100% - 1em);
  border-top: 2px solid #CCC;
  border-bottom: 1px solid #AAA;
}
.iconButton__icon {
  font-size: 1.2em;
}
.iconButton__text {
  font-weight: bold;
}
</style>

Warhol will deduce the following rules from this component definition:

  1. An element that matches the selector .button and not any other component selector with a higher specificity is an instance of the Icon button component
  2. As such, its width property must have a value of 200px, the padding must be 0.5em (or whatever number of pixels this value computes to) and the position value must be relative.
  3. The component must also have the pseudo element ::after defined with all of its styles
  4. An icon button may have child elements that use styles that either match the styles of .button__icon or the styles of .button__text

These rules are what Warhol saves as data about your pattern library. When Warhol tests a production web site against the data it extracted from a pattern library, it essentially reverses the process and complains if the data from the pattern library and the data from the production web site don't match.

It is important to stress that

  1. Warhol does not care about HTML tags, text content, image urls or the specific classes and ids that are being used to implement a component. Only the specified styles count. You could swap out the
  2. if a component or component child has a pseudo element like ::before and ::after, the same pseudo elements are mandatory when testing and the pseudo elements are required to have styles that match the pattern library
  3. Warhol has currently no concept of any sort of ordering of component children or of mandatory component children. Any component child can appear in any order in any number as long as its styles match. The same is true for component chldren's children. There will be configuration options to change this behavior to something more strict in the future.
  4. Warhol currently has no concept dynamic component states, but this will also change in the future.
  5. a pseudo element can't take the place of a component child or vice versa, even if their styles are equal.
  6. issues like HTML correctness and accessibility are firmly outside of Warhol's scope, as is the inner construction of <svg> elements

There is a lot of limitations right there, but this is by design and there will be configuration options to make the testing more strict in the future. By default, Warhol only points out design discrepancies that are an obvious problem, such as a wrong color. But Warhol can't know everything from one example element in the pattern libarary. Can an .iconButton have more than one icon? Is more than one iconButton__text allowed? Is iconButton__text even required or are icon-only buttons ok? Does the icon always have to be the first child element in an .iconButton? There is no way to know by just looking at an example, so Warhol defaults to not complain about anything that is at least plausible (which includes all of the above points about the icon button).

Future improvements to Warhol will allow you to to tighten up its test algorithms. The only way to do so right now is with the [/docs/directives/must-not-match](directives must-match and must-not-match).

Utility classes

If you want to use helper or utilitiy classes like .box-shadow or .alignLeft on your components without having them cause unexpected CSS declaration errors, check out style utilities!

Configuring components

The components field in your warhol config can contain a list of component definitions.

Field source (string, required, non-empty)

The selector for the component example(s) in the pattern library. The selector can target more than one element.

Field target (string, optional, non-empty, defaults to source)

The selector for the component implementations in the production web page. You can omit the target field if its value is equal to source.

Field name (string or null, optional, non-empty, defaults to target)

An optional human-readable name for the component. Defaults to the target selector if name is not specifed or null.

Field componentUrl (string or null, optional or required depending on the pattern lib URL)

This component's own URL, if any. Defaults to the pattern lib URL. If no pattern lib URL was specified, this field is required for each component.

Example configuration

Full example:

{
  "patternLibUrl": "https://warhol.io/patterns",
  "breakpoints": [800, 1000],
  "components": [{
    "source": ".iconButton",
    "target": ".icoBtn",
    "name": "Icon button",
    "componentUrl": "https://warhol.io/patterns/iconButton",
  }]
}

Minimal example:

{
  "patternLibUrl": "https://warhol.io/patterns",
  "breakpoints": [800, 1000],
  "components": [{
    "source": ".iconButton"
  }]
}

FAQ

  • How can I test dynamic components, such as collapsibles? At the moment there is no built-in way for Warhol to test dynamic components or anything interactive (like :hover). This feature is planned out and in even implemented in parts but it not yet ready for prime time. As a workaround you can define different component states as seperate components (eg. a component for .collapsible and an extra component for .collapsible.isOpen) and re-run tests to check the component in both states. This is just a temporary workaround! In the future Warhol will be able to automatically predict the styles in component's dynamic states with only minimal configuration overhead.