Putting an abstraction on top of the design system

Hello all,

As you probably know, switching from one design system and supporting framework to another (e.g., moving from boostrap 3 to vuetify) is a really difficult and time consuming if not anticipated.
In addition, it is sometime interesting to easily switch to an alternative design system for a specific need (e.g., switch to https://www.systeme-de-design.gouv.fr/ for a development for the french government), preferably by configuration.

To tackle those two challenges, with @ludovic we’d like to propose to build the design system of Cristal as an abstraction over several design systems (see our design page on design systems, we’ll create a proposal to choose the design systems we will support soon).

To make it more concrete, the idea is define a set of UI elements and their parameters that would form the minimal building blocks of Cristal UI (i.e., a design system API).
Then, those element will be mapper to concrete UI elements from a design system - including mapping the parameters.

For instance, say we define a CritalButton with parameters label and level (primary, secondary, tersary), the table below presents how the mapping would operate:

Abstract ComponentAPIdsfr (https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/bouton )Bootstrap 5 (https://getbootstrap.com/docs/5.3/components/buttons/)vuetify (https://vuetifyjs.com/en/components/buttons/)
Button (primary)<CristalButton level='primary'/>
  Label
</CristalButton>

 

<button class="fr-btn">
  Label
</button>
<button type="button" class="btn btn-primary">
  Label
</button>
<button class='v-btn v-btn--elevated v-theme--light bg-primary v-btn--density-default v-btn--size-default v-btn--variant-elevated'>
  Label
</button>
Button (seconday)<CristalButton level='secondary'/>
  Label
</CristalButton>

 

<button class="fr-btn fr-btn--secondary fr-btn--tertiary">
  Label
</button>
<button type="button" class="btn btn-secondary">
  Secondary
</button>
<button class='v-btn v-theme--light text-primary v-btn--density-default v-btn--size-default v-btn--variant-tonal'>
  Label
</button>
Button (tersary)<CristalButton level='tersary'/>
  Label
</CristalButton>
<button class="fr-btn">
  Label
</button>
<button type="button" class="btn btn-light">
  Label
</button>
<button class='v-btn v-theme--light text-primary v-btn--density-default v-btn--size-default v-btn--variant-outlined'>
  Label
</button>

We have identified some important point of difficulty, that are not to be overlooked before agreeing on the approach:

  • the indirection probably has a performance cost that we did not estimate
  • the indirection also has a conceptual cost as we’ll need to define an maintain the mapping between the API and the implementations
  • we will only be able to support the minimal common features of the design systems we will support, meaning that a lot of fine tuning proposed by some design systems will not be available (for instance, Boostrap 5 button has a lot of background color choices, but vuetify does not. Consequently, the API will only limit itself to a small set of color variations, and bootstrap subtleties are lost).

Let me know what you think.
Thanks

I have a very strong +1 for this abstraction. I believe this allows us to build our own API for our design system and key interface elements. This API can be exposed to our developers of Cristal but also the developers of extension. We can provide at least one implementation based on the design system / component library we choose to be our primary one. And then we can in the future change our mind without re-coding everything. We can also provide a modified version of Cristal with a custom design system (such as a Cristal UI to the French State DSFR for example) with much less work.

This has been experimented in the prototoype with multiple implementations:

Here with Vuetify (not many custom componets in Vuetify as some where just mapped to the vuetify component):

Here with DSFR (using Vue DSFR)

Here with Shoelace (a webcomponent library):

Ludovic

Thinking of this abstraction, it could be interesting to publish this as a separate project. This could be interesting for other projects.