Ratgeber

Artikel merken

Web Components: So verwendest du Code plattformübergreifend wieder

In der Software-Entwicklung herrscht Einigkeit darüber, dass wiederverwendbarer Code eine gute Idee ist. So leicht ist das aber – vor allem plattformübergreifend – gar nicht umzusetzen. Genau an dieser Stelle setzt der Web-Components-Standard an. Wir haben uns angeschaut, warum die API auch für euch einen Blick wert sein könnte.

6 Min. Lesezeit

Foto: Mesk-Photography/Shutterstock

Code mehrfach zu verwenden – oder Code von anderen Entwicklern zu kopieren und in der eigenen App zu verbauen –, stellt sich oft genug als endloser Struggle heraus. JS-Boilerplates und CSS-Klassen passen nicht und am Ende macht ihr das dann doch lieber selber. In React oder Vue geht das mit dem Wiederverwenden innerhalb des jeweiligen Frameworks zwar etwas besser und mit HTML5 gesellten sich zum Beispiel nützliche Elemente wie <video> oder <input type="date"> zu den Standardelementen. Man braucht aber nunmal oft mehr als die Standardelemente. Am liebsten hättet ihr diese selbstgebauten Codebits dann in wiederverwendbar und das am besten plattformübergreifend und nicht nur innerhalb eines Projektes. Außerdem kann einfach nicht jedes mehr oder minder häufig benötigte Element ein HTML-Standardelement werden.

Web Components sollen genau diese Lücke schließen. Der Web-Components-Standard setzt sich aus den Standards HTML Templates, Shadow DOM und Custom Elements zusammen. Kombiniert ermöglichen die zugrundeliegenden Standards es, von euch definierte HTML-Elemente an allen Stellen zu nutzen, an denen sonst nur native HTML-Elemente erlaubt sind. Frühe Versionen der Standards gab es schon vor gut fünf Jahren, sie waren aber noch nicht in allen Browsern verfügbar. Mittlerweile werden Web Components aber von allen großen Browsern unterstützt.

HTML-Templates

Das Template-Element gibt es schon länger. Wrappt ihr HTML-Code zwischen zwei template-Tags, versteckt ihr ihn vor dem Client – und er wird nicht gerendert.

HTML-Templates-Demo. (Bild: t3n/via Codepen.io)

Das template-Element sorgt dafür, dass der HTML-Code zwar geparst wird, das geparste DOM wird aber nicht eurem Dokument hinzugefügt, sondern davon abgeteilt in einem Document-Fragment gespeichert. Dieser Teil eures Codes „löst sich quasi auf“, sobald ihr ihn einem anderen DOM anhängt:

Fast fertig!

Bitte klicke auf den Link in der Bestätigungsmail, um deine Anmeldung abzuschließen.

Du willst noch weitere Infos zum Newsletter? Jetzt mehr erfahren

let template = document.querySelector('template');
document.body.appendChild(template.content);

Beim ersten Rerender bekommt ihr eine Fehlermeldung, weil template.content weg ist – ihr erinnert euch: Es hat sich aufgelöst. Deshalb müsst ihr zunächst eine Kopie davon machen:

Document.body.appendChild(template.content.cloneNode(true));

Indem ihr den Parameter auf true setzt, stellt ihr sicher, dass auch alle Kindelemente der Node mitkopiert werden. Der Template-Tag ist ideal für Situationen, in denen ihr eine HTML-Struktur mehrfach verwenden wollt, sie aber nicht zum aktuellen DOM hinzugefügt werden soll.

Custom Elements

Mit dem Custom-Elements-Standard könnt ihr eure eigenen HTML-Elemente definieren. Die ganze Geschichte basiert im Wesentlichen auf der Klassen-Syntax von ES6, das sieht ungefähr so aus:

class GreetingElement extends T3N {
// class definition goes here
}

Für die Custom Elements würde das Ganze so aussehen:

class GreetingElement extends HTMLElement{}

Vor den Web Components würde euer Browser jetzt einen Error ausspucken, man konnte HTMLElement nicht extenden. Euer Browser weiß, dass ein h1-Tag zur HTMLHeading1-Klasse gehört, aber woher soll er wissen, welchen Tag er einer selbstdefinierten Element-Klasse zuordnen soll? Zusätzlich den Klassen der nativen HTML-Elemente gibt es extra dafür ein „Custom Element Register“, euer Element könnt ihr so hinzufügen:

customElements.define(‘greeting-element‘, GreetingElement);

So stellt ihr sicher, dass der Browser jeden geparsten greeting-element-Tag mit einer neuen Instanz von GreetingElement assoziiert. Übrigens: Eure Custom Elements müssen einen Bindestrich enthalten, um sie in der Benennung von den nativen HTML-Elementen abzugrenzen. Vergesst also am besten die Idee, eine h7 zu machen – das geht nicht. Außer, dass der Constructor jedes Mal, wenn euer Custom Element gerendert werden soll, aufgerufen wird, gibt es noch eine Reihe zusätzlicher Lifecycle-Methoden:

  • connectedCallback – wird aufgerufen, wenn ein Element an ein Dokument angefügt wird. Das kann öfter als ein Mal vorkommen, zum Beispiel, wenn es bewegt oder entfernt und wieder hinzugefügt wird.
  • disconnectedCallback – ist das Gegenstück zu connectedCallback.
  • attributeChangeCallback – feuert immer dann, wenn sich Attribute ändern.

Custom-Elements-Demo. (Bild: t3n/via Codepen.io)

Würdet ihr das Element auf einer Seite nutzen wollen, sähe das so aus:

Custom-Elements-Demo (Bild: t3n/via Codepen.io)

Und native HTML-Elemente?

Wollt ihr ein natives HTML-Element extenden, sieht das Markup etwas anders aus. Wenn ihr zum Beispiel wollt, dass euer GreetingElement ein Button ist, würde das so aussehen:

class GreetingElement extends HTMLButtonElement

Dann müsst ihr noch festlegen, dass es sich hierbei um ein natives Element handelt, das geht so:

customElements.define('hello-there', GreetingElement, { extends: 'button' });

Custom-Elements-Demo (Bild: t3n/via Codepen.io)

Weil es sich um ein natives HTML-Element handelt, nutzt ihr an dieser Stelle den button-Tag anstelle eures Custom-Tags. Außerdem braucht ihr das is-Attribut, sonst weiß der Browser nicht, dass euer Custom-Element eine Art Button ist.

Klingt vielleicht erstmal kompliziert, muss aber so. Auch assistive Technologien orientieren sich zum Beispiel an diesem Markup. Jetzt könnt ihr Styling und EventHandler hinzufügen oder das Ganze in template-Tags wrappen, wenn ihr wollt. Andere können euer Custom Element in ihrem eigenen Code verwenden – über HTML-Templating, DOM-Calls und sogar ziemlich problemlos in bekannten Frameworks wie zum Beispiel AngularJS.

Zusammengefasst bringen die Custom Elements folgende Vorteile:

  • Die Möglichkeit, die HTMLElement-Klasse und ihre Unterklassen zu extenden.
  • Ein Register für die Custom Elements – über customElements.define() werden CustomElements dort abgelegt.
  • Eigene Lifecycle-Callbacks, über die ihr zum Beispiel Attributveränderungen, Element-Bildung und das Hinzufügen zum DOM verfolgen könnt.

Shadow DOM

Die Besonderheit an euren Custom Elements ist, dass ihr sie auch in anderen Anwendungen wiederverwenden wollt und eigentlich auch andere Entwickler sie wiederverwenden können sollen. Den Shadow DOM gibt es, um Konflikte zwischen Custom Element und CSS anderer Websites oder Apps zu umgehen.

Alle Elemente und Styles innerhalb eines HTML-Dokuments und innerhalb des DOM befinden sich in einem globalen Scope. Auf jedes Element auf einer Seite könnt ihr über document.querySelector() zugreifen und auf das Dokument angewandte CSS-Styles können jedes Element auswählen, egal, wo es sich befindet. Das ist cool, wenn ihr Styles auf das gesamte Dokument anwenden wollt – zum Beispiel, um an alle Elemente das gleiche box-sizing zu vergeben.

Manchmal ist das aber auch nicht cool. Manchmal braucht ihr Elemente, die nicht von globalen Styles betroffen sind, wie zum Beispiel ein Third-Party-Widget wie der Teilen-Button für Facebook oder ein Follow-Button für Twitter.  Über die Verwendung eines iframe kann sichergestellt werden, dass das Widget nicht vom CSS des Dokuments behelligt wird, in das ihr es einbinden wollt.

Genau an dieser Stelle kommt das Shadow DOM ins Spiel. Das Shadow DOM ist quasi ein DOM innerhalb des DOM – ein eigenes DOM mit eigenen Elementen und Styles, komplett unabhängig vom DOM eures Dokuments. Das Shadow DOM liegt auch Form-Elementen wie zum Beispiel dem range-input-Element oder auch Radio-Buttons zugrunde: Für ein range-input müsst ihr zum Beispiel einfach input type=“range“schreiben und bekommt dann einen Slider. Das input-Element selbst besteht allerdings aus mehreren kleineren divs, über die Track und Slider kontrolliert werden. Euer Dokument und alles, was sich darin befindet, kann nur das input-Element sehen, nicht die Elemente und Styles, die für Aussehen und Funktionalität sorgen. Erreicht wird das über den Shadow DOM.

Und wie funktioniert das Ganze konkret?

Um zu illustrieren, wie der Shadow DOM funktioniert, bauen wir einen Twitter-Button – ohne iframe – mit dem Shadow DOM. Dafür braucht ihr zuerst den Shadow Host – das native HTML-Element innerhalb des globalen DOM, an das wir unseren Shadow DOM anhängen wollen.

Shadow-DOM-Demo. (Bild: Codepen)

Im Beispiel hängen wir den Shadow DOM an ein span. Den Shadow DOM einfach an den Link zu hängen, was das Naheliegende wäre, funktioniert nicht, weil manche HTML-Elemente kein Shadow Host sein dürfen. Diese Restriktion betrifft vor allem interaktive Elemente. Um den Shadow DOM an den span anzuhängen, nutzen wir die attachShadow()-Methode.

const shadowEl = document.querySelector(".shadow-host");
const shadow = shadowEl.attachShadow({mode: 'open'});

So entsteht eine leere Shadow Root, die das Kindelement des Shadow Host ist. Die Shadow Root ist quasi der Anfang des Shadow DOM, so wie das -Element der Beginn des regulären DOM ist. Dann wollen wir unseren Shadow-Komponentenbaum ausbauen. Der Shadow-Tree ist genau wie ein DOM-Tree, nur für das Shadow-DOM. Für einen Twitter-Button braucht ihr nur ein neues <a>-Element – eigentlich genau wie der Link im vorherigen Beispiel. Stylen könnt ihr den Button, indem ihr ein Style-Element erstellt, die gewünschten Styles definiert und es dann über die appendChild()-Methode dem Shadow DOM hinzufügt. Das gesamte Beispiel findet ihr bei Codepen.io.

Kombiniert ihr die Standards, sieht der Workflow für die Erstellung und Verwendung der Web Components ungefähr so aus:

  1. Ihr erstellt eine JavaScript-Klasse (oder -Funktion), in der ihr die Funktionalität eurer Web Components spezifiziert.
  2. Ihr registriert euer neues Custom Element über die CustomElementRegistry.define() -Methode, definiert das name-Attribut und die Klasse oder Funktion, die seine Funktionalität spezifiziert und optional, von welchem Element es vererbt.
  3. Falls benötigt, fügt ihr mit der Element.attachShadow()-Methode einen Shadow DOM an euer Custom Element an. Kind-Elemente, Event-Listener und alles weitere fügt ihr wie gehabt mit regulären DOM-Methoden hinzu.
  4. Anschließend könnt ihr ein HTML-Temlate mittels <template> und <slot> definieren, wenn ihr wollt. Zum Klonen des Templates verwendet ihr, wie in Beispiel 4 ersichtlich, reguläre DOM-Methoden.
  5. Jetzt lässt sich euer Custom Element verwenden wie jedes reguläre HTML-Element, für euch und für alle anderen, die Verwendung dafür finden.

Weitere detaillierte Tutorials und Definitionen findet ihr zum Beispiel bei MDN oder in den Web Fundamentals Guidelines von Google.

Das könnte dich auch interessieren

Bitte beachte unsere Community-Richtlinien

Wir freuen uns über kontroverse Diskussionen, die gerne auch mal hitzig geführt werden dürfen. Beleidigende, grob anstößige, rassistische und strafrechtlich relevante Äußerungen und Beiträge tolerieren wir nicht. Bitte achte darauf, dass du keine Texte veröffentlichst, für die du keine ausdrückliche Erlaubnis des Urhebers hast. Ebenfalls nicht erlaubt ist der Missbrauch der Webangebote unter t3n.de als Werbeplattform. Die Nennung von Produktnamen, Herstellern, Dienstleistern und Websites ist nur dann zulässig, wenn damit nicht vorrangig der Zweck der Werbung verfolgt wird. Wir behalten uns vor, Beiträge, die diese Regeln verletzen, zu löschen und Accounts zeitweilig oder auf Dauer zu sperren.

Trotz all dieser notwendigen Regeln: Diskutiere kontrovers, sage anderen deine Meinung, trage mit weiterführenden Informationen zum Wissensaustausch bei, aber bleibe dabei fair und respektiere die Meinung anderer. Wir wünschen Dir viel Spaß mit den Webangeboten von t3n und freuen uns auf spannende Beiträge.

Dein t3n-Team

Schreib den ersten Kommentar!

Melde dich mit deinem t3n Account an oder fülle die unteren Felder aus.

Bitte schalte deinen Adblocker für t3n.de aus!

Hallo und herzlich willkommen bei t3n!

Bitte schalte deinen Adblocker für t3n.de aus, um diesen Artikel zu lesen.

Wir sind ein unabhängiger Publisher mit einem Team von mehr als 75 fantastischen Menschen, aber ohne riesigen Konzern im Rücken. Banner und ähnliche Werbemittel sind für unsere Finanzierung sehr wichtig.

Schon jetzt und im Namen der gesamten t3n-Crew: vielen Dank für deine Unterstützung! 🙌

Digitales High Five
Holger Schellkopf (Chefredakteur t3n)

Anleitung zur Deaktivierung

Artikel merken

Bitte melde dich an, um diesen Artikel in deiner persönlichen Merkliste auf t3n zu speichern.

Jetzt registrieren und merken

Du hast schon einen t3n-Account? Hier anmelden

oder