Component Structure

Guidelines on how to write and structure the CSS of components for the design system.

    Principles

    • Structured naming: All components should use a prefix and follow the BEM structure.
    • Overwritable classes: All classes should be able to be overwritable by TailwindCSS classes.
    • Inherited attributes: All attributes should be set by inheriting TailwindCSS classes.

    Structured Naming

    Prefix

    All components should start with a c- prefix. Components intended to be used on our marketing pages should start with a c_h- prefix.

    /* App */
    .c-btn {}
    
    /* Marketing pages */
    .c_h-btn {}

    BEM

    To keep the naming structure consistent, we use the BEM structure (Block, Element, Modifier) for all our design system components.

    /* Block */
    .c-btn {}
    
    /* Element */
    .c-btn__icon {}
    
    /* Modifier */
    .c-btn--green {}
    
    /* Element & Modifier */
    .c-btn__icon--green

    We try to avoid using grandchildren (i.e. name selectors in elements that are 2+ levels deep).

    /* Don't */
    .c-nav__list {}
    .c-nav__list__item {}
    
    /* Do */
    .c-nav__list {}
    .c-nav__item {}

    Overwritable Classes

    To keep all design system classes overwritable by default TailwindCSS classes, we strictly keep the specificity score of all classes as low as possible.

    Here a few examples of bad practices:

    Don't chain classes

    Avoid chaining multiple CSS classes if possible to keep specificity low. The :where pseudo-class function is a good alternative that always keeps specificity at 0.

    /* Don't */
    .c-btn--red.c-btn--disabled {}
    
    /* Do */
    :where(.c-btn--red).c-btn--disabled {}

    Don't use HTML tags

    Avoid styling HTML tags such as header or h2. Also avoid chaining a CSS class with a HTML tag, as this will increase its specificity.

    /* Don't */
    h2 {}
    
    /* Do */
    .c-heading {}
    /* Don't */
    button.c-btn {}
    
    /* Do */
    .c-btn {}

    Inherited attributes

    To keep components consistent and maintainable, we set all attributes of a class by inheriting TailwindCSS classes using the @apply directive.

    /* Don't */
    .c-btn {
      backgroundColor: green;
    }
    
    /* Do */
    .c-btn {
      @apply bg-green-500;
    }

    If an attribute is not available in TailwindCSS, we add it to the tailwind.config.js or create a custom utility class in the design-system/utilities folder.

    /* Don't */
    .c-btn {
      transform: translateY(-50%);
    }
    
    /* Do */
    module.exports = {
      theme: {
        extend: {
          translate: {
            "half": "-50%",
          }
        }
      }
    }
    
    @layer components {
      .c-btn {
        @apply -translate-y-half;
      }
    }
    
    /* Do */
    @layer utilities {
      .-translate-y-half {
        transform: translateY(-50%);
      }
    }
    
    @layer components {
      .c-btn {
        @apply -translate-y-half;
      }
    }