Web Components: Eigene HTML-Elemente erstellen | Enjyn Gruppe
Hallo Welt
Hallo Welt
Original Lingva Deutsch
Übersetzung wird vorbereitet...
Dieser Vorgang kann bis zu 60 Sekunden dauern.
Diese Seite wird erstmalig übersetzt und dann für alle Besucher gespeichert.
0%
DE Zurück zu Deutsch
Übersetzung durch Lingva Translate

235 Dokumentationen verfügbar

Wissensdatenbank

Web Components Custom Elements

Zuletzt aktualisiert: 20.01.2026 um 11:25 Uhr

Web Components: Eigene HTML-Elemente erstellen

Web Components ermöglichen Framework-unabhängige, wiederverwendbare UI-Komponenten. Lernen Sie Custom Elements, Shadow DOM und HTML Templates.

Die drei Säulen von Web Components

Technologie Funktion
Custom Elements Eigene HTML-Tags definieren
Shadow DOM Gekapseltes CSS und DOM
HTML Templates Wiederverwendbare Markup-Vorlagen

Einfaches Custom Element

// my-greeting.js
class MyGreeting extends HTMLElement {
    constructor() {
        super();
        this.innerHTML = `<p>Hallo, Welt!</p>`;
    }
}

// Element registrieren (Name muss Bindestrich enthalten!)
customElements.define('my-greeting', MyGreeting);
<!-- Verwendung im HTML -->
<my-greeting></my-greeting>

Custom Element mit Attributen

class UserCard extends HTMLElement {
    // Beobachtete Attribute definieren
    static get observedAttributes() {
        return ['name', 'email', 'avatar'];
    }

    constructor() {
        super();
        this.attachShadow({ mode: 'open' });
    }

    connectedCallback() {
        // Wird aufgerufen wenn Element ins DOM eingefügt wird
        this.render();
    }

    attributeChangedCallback(name, oldValue, newValue) {
        // Wird aufgerufen wenn beobachtetes Attribut sich ändert
        if (oldValue !== newValue) {
            this.render();
        }
    }

    render() {
        const name = this.getAttribute('name') || 'Unbekannt';
        const email = this.getAttribute('email') || '';
        const avatar = this.getAttribute('avatar') || 'default.png';

        this.shadowRoot.innerHTML = `
            <style>
                .card {
                    display: flex;
                    align-items: center;
                    padding: 1rem;
                    border: 1px solid #ddd;
                    border-radius: 8px;
                    gap: 1rem;
                }
                img {
                    width: 50px;
                    height: 50px;
                    border-radius: 50%;
                }
                h3 { margin: 0; }
                p { margin: 0; color: #666; }
            </style>
            <div class="card">
                <img src="${avatar}" alt="${name}">
                <div>
                    <h3>${name}</h3>
                    <p>${email}</p>
                </div>
            </div>
        `;
    }
}

customElements.define('user-card', UserCard);
<!-- Verwendung -->
<user-card
    name="Max Mustermann"
    email="max@example.com"
    avatar="avatar.jpg">
</user-card>

Shadow DOM erklärt

class IsolatedComponent extends HTMLElement {
    constructor() {
        super();

        // Shadow DOM erstellen
        // mode: 'open' = von außen zugänglich via element.shadowRoot
        // mode: 'closed' = komplett isoliert
        const shadow = this.attachShadow({ mode: 'open' });

        // Styles im Shadow DOM sind GEKAPSELT
        // Sie beeinflussen nicht den Rest der Seite
        shadow.innerHTML = `
            <style>
                /* Diese Styles gelten NUR innerhalb des Shadow DOM */
                p { color: red; font-weight: bold; }
                .container { padding: 20px; background: #f0f0f0; }
            </style>
            <div class="container">
                <p>Dieser Text ist rot - nur hier!</p>
            </div>
        `;
    }
}

HTML Templates und Slots

<!-- Template im HTML definieren -->
<template id="card-template">
    <style>
        .card {
            border: 2px solid #333;
            border-radius: 10px;
            padding: 1rem;
        }
        .header {
            background: #333;
            color: white;
            padding: 0.5rem;
            margin: -1rem -1rem 1rem -1rem;
            border-radius: 8px 8px 0 0;
        }
    </style>
    <div class="card">
        <div class="header">
            <slot name="title">Standard-Titel</slot>
        </div>
        <div class="content">
            <slot>Standard-Inhalt</slot>
        </div>
    </div>
</template>

<script>
class FancyCard extends HTMLElement {
    constructor() {
        super();
        const shadow = this.attachShadow({ mode: 'open' });

        // Template klonen und einfügen
        const template = document.getElementById('card-template');
        shadow.appendChild(template.content.cloneNode(true));
    }
}

customElements.define('fancy-card', FancyCard);
</script>

<!-- Verwendung mit Slots -->
<fancy-card>
    <span slot="title">Mein Titel</span>
    <p>Dieser Inhalt geht in den Standard-Slot</p>
</fancy-card>

Lifecycle Callbacks

class LifecycleDemo extends HTMLElement {
    constructor() {
        // Immer zuerst super() aufrufen!
        super();
        console.log('1. constructor - Element erstellt');
    }

    connectedCallback() {
        // Element wurde ins DOM eingefügt
        console.log('2. connectedCallback - Im DOM');
        this.startTimer();
    }

    disconnectedCallback() {
        // Element wurde aus DOM entfernt
        console.log('3. disconnectedCallback - Aus DOM entfernt');
        this.stopTimer();
    }

    adoptedCallback() {
        // Element wurde in neues Dokument verschoben
        console.log('4. adoptedCallback - Dokument gewechselt');
    }

    attributeChangedCallback(name, oldVal, newVal) {
        console.log(`5. Attribut "${name}": ${oldVal} → ${newVal}`);
    }

    static get observedAttributes() {
        return ['data-count'];
    }

    startTimer() {
        this.interval = setInterval(() => {
            const count = parseInt(this.dataset.count || 0) + 1;
            this.dataset.count = count;
        }, 1000);
    }

    stopTimer() {
        clearInterval(this.interval);
    }
}

Events in Web Components

class ClickCounter extends HTMLElement {
    constructor() {
        super();
        this.count = 0;
        this.attachShadow({ mode: 'open' });

        this.shadowRoot.innerHTML = `
            <button>Klicks: <span>0</span></button>
        `;

        this.button = this.shadowRoot.querySelector('button');
        this.span = this.shadowRoot.querySelector('span');

        this.button.addEventListener('click', () => {
            this.count++;
            this.span.textContent = this.count;

            // Custom Event nach außen dispatchen
            this.dispatchEvent(new CustomEvent('count-changed', {
                detail: { count: this.count },
                bubbles: true,      // Event steigt im DOM auf
                composed: true      // Event durchdringt Shadow DOM
            }));
        });
    }
}

customElements.define('click-counter', ClickCounter);
<!-- Event von außen abfangen -->
<click-counter id="counter"></click-counter>

<script>
document.getElementById('counter')
    .addEventListener('count-changed', (e) => {
        console.log('Neuer Count:', e.detail.count);
    });
</script>

Styling von außen ermöglichen

class ThemableButton extends HTMLElement {
    constructor() {
        super();
        this.attachShadow({ mode: 'open' });

        this.shadowRoot.innerHTML = `
            <style>
                button {
                    /* CSS Custom Properties können von außen gesetzt werden */
                    background: var(--btn-bg, #007bff);
                    color: var(--btn-color, white);
                    padding: var(--btn-padding, 10px 20px);
                    border: none;
                    border-radius: var(--btn-radius, 5px);
                    cursor: pointer;
                }
                button:hover {
                    opacity: 0.9;
                }
            </style>
            <button><slot>Button</slot></button>
        `;
    }
}

customElements.define('themable-button', ThemableButton);
<!-- Styling von außen -->
<style>
    themable-button {
        --btn-bg: #28a745;
        --btn-color: white;
        --btn-radius: 20px;
    }
</style>

<themable-button>Grüner Button</themable-button>
💡 Tipp: Web Components funktionieren in allen modernen Browsern ohne Framework. Sie sind ideal für Design-Systeme und wiederverwendbare UI-Bibliotheken, die framework-agnostisch sein sollen.

Weitere Informationen

Enjix Beta

Enjyn AI Agent

Hallo 👋 Ich bin Enjix — wie kann ich dir helfen?
120