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

330 Dokumentationen verfügbar

Wissensdatenbank

Web Components Custom Elements

Zuletzt aktualisiert: 14.07.2026 um 12:29 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

Texterstellung mit KI-Unterstützung

Enjix Beta

Enjyn AI Agent

Hallo 👋 Ich bin Enjix — wie kann ich dir helfen?
LLMs können Fehler machen. Ihre Nachrichten werden an Google Gemini weitergeleitet.
120