Skip to content

Styling richtlijnen voor componenten ​

Styling in die-core componenten ​

Bij het ontwikkelen van componenten in onze die-core Lit bibliotheek hanteren we specifieke richtlijnen om consistentie, onderhoudbaarheid en herbruikbaarheid te garanderen.

Componenten en styling structuur ​

In die-core volgen we een gestandaardiseerde naamgeving en structuur:

  • HTML tag namen beginnen met dcr- prefix (bv. dcr-notification)
  • Component klassen gebruiken PascalCase met Dcr prefix (bv. DcrNotification)
  • Styling staat in aparte .scss bestanden (bv. dcr-notification.styles.scss)
  • Deze .scss bestanden worden automatisch gecompileerd naar .ts files en geïmporteerd als .js
typescript
// dcr-notification.ts
import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';
import styles from './dcr-notification.styles.js';

@customElement('dcr-notification')
export class DcrNotification extends LitElement {
  static styles = styles;

  render() {
    return html`
      <div class="notification">
        <div class="header">
          <span class="title">${this.title}</span>
          <div class="icon">${this.renderIcon()}</div>
        </div>
        <div class="content">${this.message}</div>
      </div>
    `;
  }
}

Design tokens gebruiken in SCSS ​

In die-core gebruiken we design tokens uit de CDS (Component Design System) bibliotheek:

scss
// dcr-notification.styles.scss
@use '@diekeure/cds-tokens' as cds;

.notification {
  border-radius: 4px;
  background-color: rgb(cds.get('cds.sys.color.surface-container'));
}

.header {
  display: flex;
  justify-content: space-between;
  padding: 12px;
  color: rgb(cds.get('cds.sys.color.on-surface'));
}

.title {
  font-weight: 600;
}

.icon {
  height: 20px;
  width: 20px;
  color: rgb(cds.get('cds.sys.color.primary'));
}

Deze tokens worden in de compilatiefase omgezet naar CSS variabelen:

css
/* Gecompileerde uitvoer */
.notification {
  border-radius: 4px;
  background-color: var(--cds-sys-color-surface-container, 255, 218, 212);
}

Semantische classnamen ​

In die-core gebruiken we semantische classnamen die het doel of de functie van een element beschrijven, niet hoe het eruitziet:

scss
// Goede semantische naamgeving in .styles.scss
.notification {
  /* ... */
}
.header {
  /* ... */
}
.content {
  /* ... */
}
.icon {
  /* ... */
}

Beknopte en duidelijke naamgeving ​

Dankzij Shadow DOM in Lit componenten kunnen we beknopte namen gebruiken zonder risico op conflicten:

scss
// Eenvoudige, duidelijke naamgeving in .styles.scss file
.header {
  /* ... */
}
.title {
  /* ... */
}
.icon {
  /* ... */
}

Waarom geen utility classes in die-core? ​

We vermijden utility classes zoals .flex, .m-bs-xs, of .icon-right in die-core om verschillende redenen:

Probleempunten van utility classes in componenten ​

  1. Mixing paradigms: Het gebruik van utility classes zoals icon-right en label-small in een componentenbibliotheek mengt twee verschillende architecturale benaderingen (utility CSS vs. component-based CSS)

  2. Poor semantics: Classes die presentatiedetails beschrijven (positie, grootte) in plaats van doel maken code minder onderhoudbaar en moeilijker te begrijpen

  3. Component independence: In een Lit componentenbibliotheek moet elke component zelfstandig zijn met betekenisvolle classnamen die de domeinlogica weerspiegelen

  4. Shadow DOM considerations: Lit componenten gebruiken Shadow DOM, waardoor utility classes een onlogische keuze zijn binnen het encapsulatie-model

  5. Gefragmenteerde styling: Utility classes beschrijven typisch slechts één CSS-eigenschap, wat leidt tot gefragmenteerde styling binnen componenten:

    • Een class als label-medium beschrijft enkel het font, maar zegt niets over de kleur of andere eigenschappen
    • Een class als icon-right regelt alleen de positie, maar niet de grootte of kleur van het icoon
    • Dit vereist meerdere classes op één element, wat het moeilijk maakt om de volledige styling van een component te begrijpen
  6. Drift naar multi-property utility classes: Het is verleidelijk om utility classes uit te breiden met meer eigenschappen dan hun naam suggereert:

    scss
    /* Begint als een positie-class, maar groeit naar veel meer */
    .icon-right {
      margin-left: auto; /* Dit past bij de naam */
      width: 24px; /* Maar dit gaat over dimensie, niet positie */
      height: 24px; /* Ook dimensie */
      color: red; /* Kleur heeft niets met positie te maken */
      cursor: pointer; /* Interactie-eigenschap */
    }

    Dit maakt de class onvoorspelbaar en in strijd met de naam, wat leidt tot verwarring en bugs.

  7. Moeilijk te onderhouden: Bij wijzigingen in het ontwerp moet je meerdere utility classes aanpassen in plaats van één semantische class:

    html
    <!-- Moeilijk te onderhouden: meerdere utility classes -->
    <span class="label-medium icon-right text-primary m-bs-xs">Status</span>
    
    <!-- Beter te onderhouden: één semantische class -->
    <span class="status-label">Status</span>

Voorbeelden van onjuiste en juiste naamgeving ​

scss
/* NIET doen in die-core .styles.scss bestanden: */
.label-medium {
  /* ... */
}
.label-small {
  /* ... */
}
.icon-right {
  /* ... */
}

/* WEL doen: */
.label {
  /* ... */
}
.icon {
  /* ... */
}
.status {
  /* ... */
}

Verschil met Campus ​

In ons Campus platform hanteren we een andere benadering voor styling:

Utility-first approach in Campus ​

Campus maakt gebruik van een utility-first CSS benadering met gestandaardiseerde classes:

html
<!-- Voorbeeld van utility classes in Campus -->
<div class="flex justify-between items-center p-xs surface-container corner-m">
  <h3 class="body-large weight-semibold">Cursus details</h3>
  <button class="pi-xs p-b-2xs primary corner-m">Bewerken</button>
</div>

Waarom utility classes WEL werken in Campus ​

In Campus zijn utility classes juist een goede keuze om verschillende redenen:

  1. Page layouts en UI componenten: Campus bevat hoofdzakelijk pagina-layouts en UI-componenten buiten Shadow DOM, waar utility classes effectief zijn voor snelle ontwikkeling

  2. Consistente utility framework: De utility classes in Campus zijn onderdeel van een vast utility framework binnen CDS, wat zorgt voor consistentie en voorspelbaarheid

  3. Angular compound components: Voor compound components in Angular (buiten Shadow DOM) bieden utility classes flexibiliteit zonder de overhead van nieuwe CSS te schrijven

  4. Snelle iteratie: Campus interfaces vereisen vaak snelle iteratie en aanpassingen, waarbij utility classes efficiënter werken dan het steeds bijwerken van component-specifieke stijlen

  5. Geen Shadow DOM encapsulatie: Zonder Shadow DOM is er een duidelijke scheiding tussen pagina-layout en componenten, waardoor utility classes makkelijker te beheren zijn

Voordelen in Campus context ​

In Campus biedt deze utility-first aanpak voordelen:

  1. Ontwikkelsnelheid: Snelle UI-ontwikkeling zonder steeds nieuwe CSS te schrijven
  2. Consistentie: Vooraf gedefinieerde waarden zorgen voor een consistent ontwerp
  3. Schaalbaarheid: Makkelijk aan te passen en uit te breiden voor grote applicaties

Hoe te kiezen tussen die-core en Campus stijl ​

Gebruik deze richtlijnen om te bepalen welke stijl je moet toepassen:

ContextAanbevolen aanpak
die-core componentSemantische classnamen in .styles.scss bestanden met CDS tokens
Campus UIUtility classes voor snelle ontwikkeling
Aangepaste componenten in CampusHybride: semantische basisstructuur met utility classes voor verfijning

Praktische voorbeelden ​

die-core component (correct) ​

typescript
// dcr-status-badge.ts
import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';
import styles from './dcr-status-badge.styles.scss';

@customElement('dcr-status-badge')
export class DcrStatusBadge extends LitElement {
  static styles = styles;

  render() {
    return html`
      <div class="badge">
        <span class="icon">${this.renderIcon()}</span>
        <span class="text">${this.status}</span>
      </div>
    `;
  }
}
scss
// dcr-status-badge.styles.scss
@use '@diekeure/cds-tokens' as cds;

.badge {
  display: inline-flex;
  align-items: center;
  border-radius: 4px;
  padding: 4px 8px;
  background-color: rgb(cds.get('cds.sys.color.primary-container'));
}

.icon {
  margin-right: 4px;
  color: rgb(cds.get('cds.sys.color.primary'));
}

.text {
  font-size: 14px;
  color: rgb(cds.get('cds.sys.color.on-primary-container'));
}

Campus voorbeeld (utility-first) ​

html
<div class="flex items-center surface-container-low pi-2xs p-b-3xs corner-s primary-text">
  <span class="m-ie-2xs"><i class="fas fa-info-circle"></i></span>
  <span class="label-medium">Status informatie</span>
</div>

Conclusie ​

Bij het ontwikkelen van componenten in die-core, focus op semantische, betekenisvolle classnamen in je .styles.scss bestanden die het doel van elementen beschrijven. Vermijd utility classes of presentatie-gerichte naamgeving zoals .icon-right of .label-small. Gebruik in plaats daarvan CDS design tokens via de @use '@diekeure/cds-tokens' as cds; import.

Door deze richtlijnen te volgen, creëren we een consistente, onderhoudbare componentenbibliotheek die gemakkelijk te begrijpen en te gebruiken is door alle ontwikkelaars in het team.