Du nutzt jeden Tag HTML-Elemente wie <input>, <select> oder <video>. Aber hast du dich mal gefragt, warum du nicht einfach dein eigenes Element bauen kannst? Eins, das genau das tut, was du brauchst - ohne ein ganzes Framework mitzuschleppen?
Genau das machen Web Components. Und das Beste: Sie sind ein nativer Browser-Standard. Kein npm install, kein Build-Step, kein Framework-Lock-in. Einfach JavaScript und der Browser.
Web Components sind eigene HTML-Elemente mit Shadow DOM, Templates und Custom Elements API. Sie funktionieren in jedem Framework - oder ganz ohne. Perfekt fuer wiederverwendbare UI-Bausteine.
Was sind Web Components? 🤔
Web Components basieren auf drei Kern-Technologien, die in jedem modernen Browser eingebaut sind:
- Custom Elements - Damit definierst du eigene HTML-Tags wie
<my-button> - Shadow DOM - Kapselt Styles und Markup, damit nichts nach aussen leakt
- HTML Templates -
<template>und<slot>fuer wiederverwendbare Strukturen
Das Zusammenspiel dieser drei APIs ergibt Komponenten, die sich anfuehlen wie native Browser-Elemente - weil sie es im Grunde auch sind.

Dein erstes Custom Element 🧱
Lass uns direkt loslegen. So definierst du ein eigenes Element:
class MyGreeting extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
const name = this.getAttribute('name') || 'Welt';
this.shadowRoot.textContent = '';
const style = document.createElement('style');
style.textContent = `
:host {
display: inline-block;
padding: 1rem;
background: #f0f9ff;
border-radius: 8px;
font-family: system-ui;
}
.greeting { color: #0369a1; font-weight: bold; }
`;
const span = document.createElement('span');
span.className = 'greeting';
span.textContent = 'Hallo, ' + name + '! 👋';
this.shadowRoot.append(style, span);
}
}
customElements.define('my-greeting', MyGreeting);
Und in deinem HTML verwendest du es einfach so:
<my-greeting name="Developer"></my-greeting>
Das war's. Kein Import, kein Bundler, kein Framework. Der Browser weiss jetzt, was <my-greeting> ist.
Shadow DOM: Dein privates Styling 🔒
Das Shadow DOM ist der eigentliche Gamechanger. Kennst du das Problem, dass dein CSS ploetzlich andere Teile der Seite kaputt macht? Oder dass globale Styles in deine Komponente reinbluten?
Shadow DOM loest das komplett. Alles, was im Shadow Root lebt, ist vom Rest der Seite isoliert:
class IsolatedCard extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
const style = document.createElement('style');
style.textContent = '/* Diese Styles gelten NUR hier drin */ p { color: red; font-size: 24px; }';
const p = document.createElement('p');
p.textContent = 'Ich bin rot und gross - aber nur hier drin!';
shadow.append(style, p);
}
}
customElements.define('isolated-card', IsolatedCard);
Das p { color: red; } hat null Auswirkung auf den Rest deiner Seite. Und umgekehrt kann kein globaler Style deinen Shadow DOM erreichen (ausser CSS Custom Properties - die sind explizit als API gedacht).
Lifecycle Callbacks ♻️
Custom Elements haben eigene Lifecycle-Hooks, aehnlich wie du sie von Angular oder React kennst:
| Callback | Wann? |
|---|---|
connectedCallback() | Element wird ins DOM eingefuegt |
disconnectedCallback() | Element wird aus dem DOM entfernt |
attributeChangedCallback() | Attribut wird geaendert |
adoptedCallback() | Element wird in ein neues Dokument verschoben |
Besonders attributeChangedCallback ist spannend - damit kannst du reaktiv auf Attributaenderungen reagieren:
class ReactiveElement extends HTMLElement {
static get observedAttributes() {
return ['theme'];
}
attributeChangedCallback(name, oldVal, newVal) {
if (name === 'theme') {
this.shadowRoot.querySelector('.container')
.classList.toggle('dark', newVal === 'dark');
}
}
}
Slots: Content Projection 🎰
Mit <slot> kannst du Inhalte von aussen in deine Komponente projizieren - vergleichbar mit ng-content in Angular oder children in React:
class FancyCard extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
// Using template for declarative Shadow DOM
const template = document.createElement('template');
template.innerHTML = [
'<style>',
'.card { border: 2px solid #e2e8f0; border-radius: 12px; overflow: hidden; }',
'.header { background: #1e293b; color: white; padding: 1rem; }',
'.body { padding: 1rem; }',
'</style>',
'<div class="card">',
' <div class="header"><slot name="header">Default Header</slot></div>',
' <div class="body"><slot>Default Content</slot></div>',
'</div>'
].join('');
this.shadowRoot.append(template.content.cloneNode(true));
}
}
customElements.define('fancy-card', FancyCard);
<fancy-card>
<h3 slot="header">Mein Titel</h3>
<p>Dieser Content wird in den Default-Slot projiziert.</p>
</fancy-card>
Web Components + Frameworks 🤝
Und hier wird's richtig interessant: Web Components funktionieren in jedem Framework. Du baust die Komponente einmal und nutzt sie ueberall:
<!-- In Angular -->
<my-greeting [attr.name]="userName"></my-greeting>
<!-- In React -->
<my-greeting name={userName} />
<!-- In Vue -->
<my-greeting :name="userName"></my-greeting>
<!-- In plain HTML -->
<my-greeting name="Developer"></my-greeting>
Das ist der grosse Vorteil gegenueber Framework-spezifischen Komponenten. Dein Design-System funktioniert ueberall - egal ob das Team Angular, React oder Vue nutzt.
Wann Web Components, wann Framework? 🤷
Web Components sind kein Ersatz fuer Angular oder React. Sie sind eine Ergaenzung. Hier eine Faustregel:
- Web Components - Fuer wiederverwendbare UI-Primitives (Buttons, Cards, Modals), die framework-unabhaengig sein sollen
- Framework-Komponenten - Fuer Business-Logik, Routing, State Management und alles, was eng mit deiner App verzahnt ist
Grosse Firmen wie Google (mit Lit), Adobe und SAP setzen massiv auf Web Components fuer ihre Design-Systeme. Das ist kein Zufall.
Praxis-Tipps 💡
- Nutze Lit (lit.dev) als duenne Abstraktion ueber der nativen API - spart Boilerplate
- CSS Custom Properties (
--my-color) sind dein API fuer Theming durch den Shadow DOM - Verwende
:hostund:host-context()fuer kontextabhaengiges Styling - Teste mit
@open-wc/testing- speziell fuer Web Components gemacht
Fazit 🎯
Web Components sind kein Hype, der morgen wieder verschwindet. Sie sind ein Webstandard, der in jedem Browser laeuft. Wenn du wiederverwendbare UI-Bausteine brauchst, die nicht an ein Framework gebunden sind, sind sie die richtige Wahl.
Der Einstieg ist ueberraschend einfach - du brauchst nur Vanilla JavaScript und die Browser-APIs. Und wenn du mehr Komfort willst, gibt dir Lit eine schlanke Abstraktion ohne den Overhead eines Full-Stack-Frameworks.
