Sparking joy in a design system

by Marinella — UX Manager in Radicalbit

Any frontend developer will have experienced the pleasure of opening the newly released page with the Chrome inspector finding a clear and semantic clean code. Not even Marie Kondo could do better!
How many times has it happened to you to review some old code and think: “gosh, how bad is this? ? who assigned the classes? What a mess!“.
At first glance, it might be the work of the former nice but bungling colleague, but Git doesn’t lie and Visual Studio quickly reveals the author — what the heck — it was me to create this obscenity!
There might be a positive side: you have improved your skills over the time, and the code you write today is neater than yesterday.
When working as a team on a complex and rapidly evolving product, this individual process takes its toll: a shared nomenclature system must be adopted then.

“Tidying up should be about re-establishing a
balance between people, their belongings
and the house they live in.”
Marie Kondo

Teamwork

As naming things is a rare talent, adopting a naming convention helps teamwork and turns the giant question mark about how to name an object into an automatic process that follows precise rules, and that — at best- someone has defined before you. It’s reassuring to have both a tidy closet and a uniform code, isn’t it?

Designing an interface thinking in BEM

An interface designer, able to reach a good level of abstraction, may already have in mind the html structure of components while drawing them, from the draft to Figma.
After reasoning about the user experience and the aesthetic research of the interface, the designer can focus on assembling and naming the components and levels to prepare the code development process, anticipating potential development problems.

BEM provides a model that helps to reason in these terms: association between Figma and BEM
component = block,
layer / group = element,
variant = identifier, works well.
Just as our cute Japanese heroine suggests organizing spaces in the simplest way possible, dividing the garments according to a logic grouped by type, so also in designing a mockup it is useful to declutter and group by sets and subsets according to a defined protocol.

It is essential to discuss with the technicians to validate feasibility and nomenclature, and with the help of the FE colleagues, to work on functional and shared solutions for this “chest of drawers” ​​which will mainly serve them.

“Words can be bullets, but they can also be rescue teams”
Jón Kalman Stefánsson

Block_element — identifier

BEM is a convention created in 2007 (read here how it was born) to improve collaboration in frontend development.
Thanks to BEM we are able to assign to the classes of our DOM elements names that are explicit about the type and hierarchy of their content:
Block is the main container that contains a set of other elements, even at multiple nesting levels: our “chest of drawers”, to clarify
Element is the child of the block and distinguishes each of the main sections that contain other elements, the “box that divides the socks”, simply
Identifier is an indicator that changes the appearance of the block or element, as if the labels of the containers transform the shirts into wool sweaters.

An example: l-header, a component of our design system, has an intrinsic structure that can contain strings, objects or other independent components.

styles.less

.l-header {
display: flex;
flex-direction: row;
padding: 1rem;
flex-wrap: wrap;
gap: 1rem;
align-items: stretch;


&__title {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
order: 1;
flex-grow: 1;
}

&__details {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-content: flex-end;
order: 2;
flex-grow: 2;
flex-wrap: wrap;
gap: .5rem;
}

&__actions {
display: flex;
flex-direction: column;
justify-content: space-between;
order: 3;
flex-grow: 0;
flex-wrap: wrap;
gap: .5rem;
}

&--dark-mode {
background: @rdb-dark;
color: @rdb-white;
}
}

index.js

<div className={`l-header ${modifier || ''}`}>

<div className="l-header__title">
<PageTitle
subtitle={subtitle}
icon={icon}
isEditable={isEditable}
onTitleChange={onChange}
title={text}
/>
</div>
{details && (
<div className="l-header__details">

{details.one && details.one}
{details.two && details.two}
{details.three && details.three}

</div>
)}
{actions && (
<div className="l-header__actions">

{actions.one && actions.one}
{actions.two && actions.two}

</div>
)}
</div>

“There are only two hard problems in Computer Science:
cache invalidation and naming things”
Phil Karlton

Robust CSS architecture

In Radicalbit we have chosen BEM as the reference model among the many conventions available (OOCSS, SMACSS, SUITCSS, Atomic) because its peculiarities are perfectly adaptable to the needs of a design system:

Clear Structure

Having a semantics similar to the React structure allows us to think in terms of components: each component is an easy block to intercept and recognize within the project also in the compiled html.

<div class="l-header ">
<div class="l-header__title">
<div class="c-section-title">
<h1 class="c-section-title__title">
Microfrontend Title
</h1>
<div class="c-section-title__props">
Title props
</div>
</div>
</div>
<div class="l-header__details">
<div class="c-detail">
<span class="c-detail__label">Detail label</span>
<h3 class="c-detail__content">Detail </h3>
</div>
<div class="c-detail"></div>
<div class="c-detail"></div>
</div>
<div class="l-header__actions"></div>
</div>

Modularity
Each block is made up of distinct units, each performing a specific task and capable of interacting with the others, or being used in different patterns.
Below is our l-header used in various sections of the RNA interface, our MLOps Platform.

Reusability
Each component, while maintaining its properties, can change shape or color to match its parent or its identifier.
This is how our l-header changes its appearance based on context and content.In this case the product has the structure of our design system but in light mode and with a different primary color in our product GoLive.

ABEM: a useful adaptation of BEM

Distinguishing a room from a wardrobe and a wardrobe from a drawer is natural when we tidy up our house. When it comes to a design system, things become more complicated.
Fortunately, some specificities of our method come to the rescue.
The code shared so far has one more module than the Block__element– identifier, in fact a more recent declination called ABEM (*) allows us a further classification and greater flexibility.
A (tomic) BEM defines the type of block with a prefix of a single letter, while the classes atomic allows the use of global styles, limiting the known problem of stiffness of the original system.
Our pure BEM react component could have looked like this:

<div className={`l-header l-header--$ {modifier || ''}`}>

instead we have chosen to free the modifier class from the constraint of the containing block

<div className={`l-header $ {modifier || ''}`}>

In this way, we can also dynamically manage state classes or helpers better described below.

Selector specificity

The ABEM structure is extremely interesting thanks to the openness of the atomic classes but it’s not close enough to the desired solution. For our structure is ideal to use the self explanatory nomenclature prefix as suggested in this article. We can distinguish the type of block in order to recognize the genre of our selector:

  • Module layout l- l-header l -sidebar l-modal
    These modules have no aesthetic elements and are used exclusively to position components and structure the layout of an application.
  • Component c- c-toolbox c-detail c-tab c-button
    They form the backbone of an application and contain all the features for a standalone component.
  • Helpers h- h-show h-hide
    These utility classes have a single function (and are commonly used for positioning or visibility).
  • States is- has- is-visible has-loaded
    Indicates the different states a c component can have.

Semantics

Now that you can give your React project a neat style, do you think you can avoid wondering if the element you are using is a title, a paragraph, a label, or a list? Chill out!

Classifying each object of the dom according to our model does not relieve us from the need to maintain correct semantics in the html by assigning the appropriate tag to the content type, as the style-free page must maintain correct accessibility — for example for automatic code reading systems useful for the blind people and google algorithms, among others.

“Nomen omen (a name, a destiny)”

Naming consistency

The hardest task of all: naming objects so that they are generic enough to be modular, while maintaining the descriptive ability of their content.

Do you really want to call c-consumptions the bar chart block that shows the consumptions in the table?
Indeed, you are creating this new component to show customers’ consumption, but this same component could be useful, for example, to visualize the efficiency detail of a service in another environment where the name could be misleading.
So let’s call it c-chart-micro in order to have a wider level of granularity and, possibly, make the chart an interchangeable component, with a chart area or a small pie chart.

Spring cleaning the codebase

As every April in the domestic habits of European households, even here in Radicalbit it’s time to”spring cleaning”: actually, we are giving a refresh to the design system, creating new design patterns, renewing the existing ones and getting rid of those that did not “give us joy”.
Recently, we are also putting a big effort on moving our Frontend architecture towards a “micro-frontend” approach.

Wanting to hear more? Stay tuned.

We provide Event Stream Processing products designed to manage the entire data lifecycle over streaming oriented platforms, with Machine Learning integration.