States

State definitions allow you to express unique variations of UI patterns based on the element’s current status. Examples of states include hover, focus, disabled, and any other stateful descriptor.

You can easily add states to a UI pattern using the restyle-states or restyle-state keywords.

@include restyle-define(button, (
  restyle-states: (
    hover: (
      color: ...
    ),
    focus: ( ... )
  )
));

// OR

@include restyle-define(button, (
  restyle-state(hover): (
    color: ...
  ),
  restyle-state(focus): ( ... )
));

When the UI pattern is invoked, these states will get output into the CSS as selectors.

Not just selectors

We previously talked about nesting selectors in a definition, and you might be wondering why you wouldn’t just use those.

@include restyle-define(button, (
  '&:hover': ( ... ),
  '&:focus': ( ... )
));

That would work.

But, wait, states are a bit different.

Selectors are intended to represent specific hierarchical DOM order, while states represent that state of the element.

That is, the element’s hover state will not contain a .hover child.

This is important because the representation of states is highly dependent on the app architecture (e.g. framework) being used to attribute the state.

For example, you might use jQuery to add a .hover class to an element that doesn’t normally support the :hover state. Or maybe your app uses the convention of .is-hovered

In this case, a selector would introduce a coupling between the application and your pattern library.

In reSTYLE, we work around this limitation by providing state identifiers and a way for the application owner to declare how to map the identifier to a selector that’s compatible with the application architecture.

So in our definition, we only ever refer to the state identifiers (hover, focus, etc).

Mapping state identifiers

As an application owner, you will ultimately be responsible for making sure the state identifiers are mapped to appropriate selectors.

This is done using the restyle-add-state method:

@include restyle-add-state(hover, '&:hover, .is-hovered');
@include restyle-add-state(focus, '&:focus, .is-focused');

// OR

@include restyle-add-state((
  hover: '&:hover, .is-hovered',
  focus: '&:focus, .is-focused'
));

You can also define these mappings via the restyle-config method:

@include restyle-config(state-mappings, (
  hover: '&:hover, .is-hovered',
  focus: '&:focus, .is-focused'
));

States aren’t modifiers

It’s also important to understand that states are not modifiers. Modifiers describe a concrete variation of the UI pattern. For example, a small button. With modifiers, the user must specifically request the modified variant. That is, they won’t get a small button simply by asking for a button.

With states however, like selectors, come along with the request without the user asking for them. If a button has a hover state, the user will get it when asking for a button.

Here’s a quick example to help demonstrate this.

@incude restyle-define(button, (
  color: blue,
  restyle-modifier(small): (
    font-size: 75%
  ),
  restyle-state(hover): (
    color: green
  )
));

.btn {
  @include restyle(button);
  &.small {
    @include restyle(small button);
  }
}

will output…

.btn {
  color: blue;
}
.btn:hover {
  color: green;
}

.btn.small {
  color: blue;
  font-size: 75%;
}
.btn.small:hover {
  color: green;
}