Skip to main content

+register

Mixin register is the first mixin inside the +component mixin.

It does not always have to be used. If the component has no sub-elements or mutations, this mixin can be omitted.

Its purpose is to let the component know what sub-elements it contains and which elements are bound to which mutations.

In addition, it serves for doublechecking the code written below and also for a quick overview of what the component supports/implements.

+component('button')
+register
+element('.icon')
+element('img')
+element('.text')

display: inline-block
margin: 1em
font-size: 1.25em

+____________________________
+element('.icon')
...

The mixins used in the code above: +component, +register, +element.

As you can see in example above, the CSS code of the root element of the component follows right after the register section.

In some cases it could be omitted with +mode('draft') and you can find more about this topic in the documentation of the mixin +register.

Element structure in register

In the register section we have to use the same element mixins: +element and +pseudo-element as in the code later. You just need to describe the element structure of the whole component.

+component('button')
+register
+element('.icon')
+element('img')
+element('.text')
+pseudo-element('after')

// ... CSS CODE ..

+____________________________
+element('.icon')

...
<button>
<span class="icon">
<img src="{{ iconUrl }}" />
</span>
<span class="text">
{{ buttonName }}
</span>
</button>

The mixins used in the code above: +component, +register, +element, +pseudo-element.

The parser will yell at you with warning if you forget to register any element you will use later in component. Same when you register something and forget to implement later in code.

Note that you don't use the separators in the register section.

Mutations in register

After we have registered the element structure of the component, we can register the mutations of the component and its sub-elements.

+component('button')
+register
+variant('.primary')
+variant('.secondary')
+variant('.large')
+variant('.disabled')
+context('.modal-window')
+element('.icon')
+element('img')
+state(':hover')
+element('.text')
+pseudo-element('after')

...

There are 3 types of places where the mutations can be registered:

+component('button')
+register
[A section]
+element('.icon')
[B section]
+element('img')
[B section]
+element('.text')
[B section]
+pseudo-element('after')
[C section - NOT ALLOWED]
...
  • A - root element of the component (right after/inside the +register mixin) - if you register states/variants here, it's expected that root element of this component should match this selectors. There is an exception that this is the only place where can be the context-like mutations registered. That's because +context/+responsive are applied always to outside context of the component, so registering it to some sub-elements does not make sense.

  • B - sub-elements of the component (right after/inside the +element mixin) - if component has states and variants on inside sub-elements too, as we said in "A section" above, here can be registered states/variants only (not the context-like mutations).

  • C - inside the +pseudo-elements - it's not allowed because pseudo-element technicaly cannot have class name, id, or :hover state itself. Only some of his parent elements (in most cases his direct parent element) has these states/variants.

Only registered mutations can be used later in code (with exception of mode draft).

Very important to understand:

+component('button')
+register
+variant('.primary')
+element('.icon')
+element('img')

+default
// code

+variant('.primary')
// code

+____________________
+element('.icon')
// code

+____________________
+element('img')
+default
// code

+variant('.primary')
// code

...






button {
/* code */
}
button.primary {
/* code */
}

button .icon {
/* code */
}

button img {
/* code */
}

button.primary img {
/* code */
}

Notice in example above that variant .primary is registered only in root element of the component, because now the framework knows where should be the class expected, but now you can use variant .primary in any sub-element of the component. You are just saying in each sub-element individualy if (and if yes how) the particular element looks in variant .primary which means when root element has this class.

So do not do this:

+component('button')
+register
+variant('.primary')
+element('.icon')
+element('img')
+variant('.primary')

+default
// code

+variant('.primary')
// code

+____________________
+element('.icon')
// code

+____________________
+element('img')
+default
// code

+variant('.primary')
// code

...







button {
/* code */
}
button.primary {
/* code */
}

button .icon {
/* code */
}

button img {
/* code */
}

button img.primary {
/* code */
}

This is wrong if <img> doesn't have class .primary ever. Don't register variants on every sub-element where you want to style the difference, but you just register it on element where the mutation is defined in HTML.

Aliases in register

Every +element, +pseudo-element, or mutation can be registered with alias and this way it can have more semantic and readable name.

Alias has a simple rule - it must be enclosed in curly brackets: '{alias name}' and it can contain any characters except those curly bracket (inside). The second rule is - it must be unique alias in current component.

See following examples:

+component('{button}', 'button.btn')
+register
+state('{focused}', ':focus', '.focused')
+variant('{highlighted}', '.go01-flushed')
+pseudo-element('{caret}', 'after')

+default
// code

+state('{focused}')
// code

+__________________________
+pseudo-element('{caret}')
+default
// code

+variant('{highlighted}')
// code

...

You can see usage of the alias in the example above. You don't need to set alias for every sub-element or mutation. But there are cases when it is very useful:

  • when the class name (or any other selector) is not understable/semantic:
    • +variant('{highlighted}', '.go01-flushed')

  • when the class name (or any other selector) is too long:
    • +state('{faded}', '.outdated.inactive:not(.checked):last-child')

  • when more selectors have the same visual result:
    • +state('{focused}', ':focus', '.focused')

  • when sub-element have not clear meaning:
    • +element('{badge}', '> span')

  • when pseudo-element have not clear meaning:
    • +pseudo-element('{horizontal separator}', 'before')

  • when component have too long selector or with not clear meaning:
    • +component('{button}', 'button.btn')
      (this usecase is useful mainly in our special SPOT Editor)

The result should be more clear and readable code.

Exclusive mutations in register

The register part can be used in even smarter way. You can group exclusive mutations together.

Exclusive mutations are those which it makes no sense to combine them. For example:

+component('{button}', 'button.btn')
+register
+state(':hover')
+state(':focus')
+variant('.primary')
+variant('.secondary')
+variant('.tercialy')
+variant('.small')
+variant('.medium')
+variant('.large')
+context('.modal-widow')

...

The better way to write this is:

+component('{button}', 'button.btn')
+register
+state(':hover')
+state(':focus')
+variant('{priority}', '.primary', '.secondary', '.tercialy')
+variant('{size}', '.small', '.medium', '.large')
+context('.modal-widow')

...

The result is the same - you can use all variants later the same way, but the register block is much cleaner this way.

Another option to register more exclusive variants - via placeholder ?:

+component('{button}', 'button.btn')
+register
+variant('[type="?"]', 'text', 'number', 'password')
+variant('.size-?', 'tiny', 'small', 'medium', 'large')
...

You can use a placeholder char ? in first param and then list all possible values. But later in code, you have to use the whole form, e.g.:

  ...

+default
// code

+variant('[type="number"]')
// code

+variant('.size-large')
// code

...