🇬🇧 EN

GlassKit Elements

Vollständige Referenz für alle 36 Web Components – entwickelt von Jungherz GmbH. Vanilla JS, Shadow DOM, native Formular-Teilnahme.

v1.22.3 Shadow DOM 36 Komponenten Vanilla JS

Installation

CDN (schnellste Variante)

<!-- 1. GlassKit CSS --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit@1.22/glasskit.min.css"> <!-- 2. GlassKit Elements --> <script src="https://cdn.jsdelivr.net/npm/@jungherz-de/glasskit-elements/dist/glasskit-elements.min.js"></script>

npm

npm install @jungherz-de/glasskit-elements @jungherz-de/glasskit
import '@jungherz-de/glasskit/glasskit.css'; import '@jungherz-de/glasskit-elements';

Selektiver Import

Importieren Sie nur, was Sie benötigen, für kleinere Bundles:

import '@jungherz-de/glasskit-elements/components/glk-button.js'; import '@jungherz-de/glasskit-elements/components/glk-toggle.js';

Theming

Setzen Sie data-theme auf dem <html>-Element. Alle Komponenten synchronisieren sich automatisch über einen gemeinsamen MutationObserver.

<html data-theme="dark"> <!-- or "light" --> <script> // Toggle theme const theme = document.documentElement.getAttribute('data-theme'); document.documentElement.setAttribute('data-theme', theme === 'dark' ? 'light' : 'dark'); </script>

Token-Vorgaben und color-scheme. Die Elemente legen GlassKits Token-Vorgaben einmal auf das Dokument, in @layer glasskit-defaults, damit jedes eigene Stylesheet gewinnt. Seit 1.20.0 trägt diese Ebene nur die --gl-*-Tokens. color-scheme bleibt von der Seite fern: Jedes Element setzt es auf seinem eigenen Theme-Wrapper, so passen die Liste eines Selects, ein Datumswähler oder eine Scrollleiste im Element zu dessen Theme, und die Seite behält ihr eigenes. Vorher schaltete der Import der Elemente die ganze Seite auf color-scheme: dark — Text ohne eigene Farbe wurde weiß, Links hellblau, native Bedienelemente dunkel.

Die Token-Namen bleiben global; eine eigene Komponente, die var(--gl-…, fallback) liest, bekommt GlassKits Wert. Eine Seite, die die Tokens selbst deklariert oder nur in einem Teil der Seite haben will, schaltet die Vorgaben ab — das Attribut wird beobachtet, darf also auch später kommen oder gehen:

<html data-glk-defaults="off">

Die Elemente nehmen die Tokens dann von dort, wo sie sie erben: aus glasskit.css oder aus einem eigenen Block auf einem Container um sie herum.

Dichte

Für Admin-Oberflächen, Desktop-Layouts und schmale Formulare macht data-density="compact" auf dem <html>-Element jedes Bedienelement dichter: Felder und Buttons 40px hoch statt 52 und 56, kleinere Toggles, Checkboxen und Radios, dichtere Listenzeilen und Modal-Aktionen. Die Größen sind die Dichte-Tokens von GlassKit (GlassKit 1.21.0) und erreichen so jeden Shadow Root durch Vererbung — auch die eigenen Werte eines Projekts; mit data-glk-defaults="off" kommt die Vorgabe wie jedes andere Token aus glasskit.css auf der Seite. Derselbe Observer spiegelt das Attribut auf den Theme-Wrapper jedes Elements; zum Umschalten zur Laufzeit braucht es nichts weiter.

<html data-theme="dark" data-density="compact"> <script> // Back to the default density document.documentElement.removeAttribute('data-density'); </script>

Drucken

Druckdialoge lassen Hintergrundgrafiken standardmäßig weg. Mit GlassKit 1.21.1 behalten die Teile, die einen Zustand tragen, auf Papier ihre Farben — Checkbox, Radio, Toggle, Fortschritt, der aktuelle Schritt, der gewählte Tag, der Knopf des Schiebereglers, die Tonpunkte —, auch in den Elementen. Eine dunkle Seite druckt ihre helle Schrift und ihre Flächen auf weißes Papier; eine Seite, die gedruckt werden soll, wechselt dafür ins helle Theme, und die Elemente folgen:

let printTheme = null; addEventListener('beforeprint', () => { printTheme = document.documentElement.getAttribute('data-theme'); document.documentElement.setAttribute('data-theme', 'light'); }); addEventListener('afterprint', () => { if (printTheme) document.documentElement.setAttribute('data-theme', printTheme); else document.documentElement.removeAttribute('data-theme'); });

Formular-Integration

Alle Formular-Komponenten nehmen über ElementInternals an nativen Formularen teil: Ihr Wert landet in FormData, ein Reset stellt ihn wieder her. Seit 1.20.0 erfährt das Formular auch, ob sie gültig sind. Das innere Feld prüft required, pattern, min, type="email" und Ähnliches, und das Element meldet das Ergebnis: form.checkValidity() ist false, solange ein Pflichtfeld leer ist, ein Absenden hält am ersten ungültigen Feld mit der Meldung des Browsers an, reportValidity() fokussiert es, und validity, validationMessage und willValidate antworten am Element. <glk-button type="submit"> sendet sein Formular ab, type="reset" setzt es zurück — vor 1.20.0 taten beide nichts.

Labels sind mit ihren Feldern verknüpft: Ein Screenreader benennt das Feld nach seinem label, und ein Klick auf den Labeltext fokussiert es — ebenso element.focus() und ein Klick auf ein <label for>, das das Element nennt. Der hint von <glk-input> wird als Beschreibung des Feldes vorgelesen.

Deaktiviert (seit 1.22.3): Jedes Formularelement folgt seinem eigenen disabled und einem <fieldset disabled> um es herum, wie native Bedienelemente — gedimmt, aus der Tab-Reihenfolge, keine Eingabe, ein Submit-Button sendet nichts, und FormData lässt es aus. Vorher erreichte ein Fieldset nur die Formulardaten: Die Felder darin blieben bedienbar, und ein Submit-Button schickte das Formular leer ab. Die Eigenschaft disabled spiegelt das Attribut, wie bei einem nativen Bedienelement.

<form id="settings"> <glk-input name="username" label="Username"></glk-input> <glk-toggle name="notify" label="Notifications" checked></glk-toggle> <glk-button variant="primary" type="submit">Save</glk-button> </form> <script> document.getElementById('settings').addEventListener('submit', (e) => { e.preventDefault(); const data = new FormData(e.target); console.log(Object.fromEntries(data)); // { username: "...", notify: "on" } }); </script>

Inhalts-Komponenten

<glk-title>

Gestaltete Überschrift mit Textschatten.

Page Heading
<glk-title>Page Heading</glk-title>

<glk-badge>

Inline-Status-Badge mit Farbvarianten — und mit interactive ein Filter-Chip.

Default Primary Success Warning Error
<glk-badge variant="success">Active</glk-badge>

interactive rendert den Badge als echten <button> — Zeiger, Hover-Tönung, Fokusring, per Tastatur bedienbar — und lässt ihn glk-click senden. selected markiert den aktiven Chip und wird nach aria-pressed gespiegelt. Probier die Zeile aus: sie verschiebt selected bei glk-click.

aktiv beworben pausiert erledigt offen
<glk-badge interactive selected>aktiv</glk-badge> <glk-badge interactive>beworben</glk-badge>
AttributTypWerte
variantStringprimary | success | warning (seit 1.18.0) | error
interactiveBooleanAnklickbarer Chip; aktiviert glk-click
selectedBooleanDer aktive Chip — vertieft die eigene Farbe des Badges, setzt aria-pressed

Events: glk-click, wenn interactive gesetzt ist.

<glk-avatar>

Kreisförmiger Avatar mit Initialen oder Bild.

S MD LG
<glk-avatar size="lg">JD</glk-avatar> <glk-avatar src="photo.jpg"></glk-avatar>
AttributeTypeValues
sizeStringsm | (default) | lg
srcStringImage URL

<glk-card>

Inhaltskarte mit Glaseffekt.

Card content here.
<glk-card glow>Highlighted content</glk-card>
AttributeTypeDescription
glowBooleanAdds gradient glow effect
fillBooleanStreckt die Karte auf die volle Höhe ihrer Grid- oder Flex-Zelle und macht sie zur Flex-Spalte, sodass margin-top: auto einen Fuß nach unten schiebt (seit 1.8.0). Die Karte gibt ihrer Zelle nach: Inhalt, der nicht umbrechen kann – etwa ein Listen-Untertitel mit nowrap –, wird mit Ellipse abgeschnitten, statt die Karte zu verbreitern (seit 1.15.2)

<glk-divider>

<glk-divider></glk-divider>

<glk-status>

Statushinweis mit Nachricht.

<glk-status message="No results found"></glk-status>

<glk-empty>

Leerzustand für Listen und Ergebnisseiten: Icon-Fläche, Titel, kurzer Text und eine Aktion. Ein leerer title oder text blendet sein Element aus.

Buchen
<glk-empty title="Noch keine Buchungen" text="…"> <svg viewBox="0 0 24 24">…</svg> <glk-button slot="action" size="sm">Buchen</glk-button> </glk-empty>
AttributTypWerte
titleStringÜberschrift; leer = ausgeblendet
textStringGedämpfter Text; leer = ausgeblendet

Slots: Standard (ein <svg>-Icon; ein Kreis als Rückfall), action. Parts: empty, icon, title, text, action.

Buttons

<glk-button>

Glas-gestalteter Button mit drei Varianten und Größenoptionen.

Primary Secondary Tertiary
<glk-button variant="primary" size="auto">Save</glk-button>
AttributeTypeValues
variantStringprimary | secondary | tertiary
sizeStringsm | md | lg | auto
disabledBooleanDisables the button
typeStringbutton | submit | reset — submit und reset wirken auf das Formular des Elements (seit 1.20.0)

Events: glk-click

type="submit" sendet das Formular ab, in dem das Element steht, type="reset" setzt es zurück — erst wenn der Klick fertig aufgestiegen ist, sodass ein Listener mit preventDefault() auf dem Klick es verhindert, wie bei einem nativen Button. Ein Formular mit ungültigen Feldern sendet nicht und zeigt die Meldung des Browsers. Das submit-Event nennt das Element als submitter; .form ist sein Formular, und element.click() wirkt wie ein Klick. aria-expanded, aria-haspopup und aria-pressed am Element werden an den nativen Button im Inneren weitergereicht, den Screenreader lesen (seit 1.20.0).

<glk-pill>

Kleiner kreisförmiger Icon-Button (46x46px).

<glk-pill label="Menu"> <svg viewBox="0 0 24 24">...</svg> </glk-pill>
AttributeTypeDescription
labelStringAccessible aria-label
disabledBooleanDisables the button

aria-expanded, aria-haspopup und aria-pressed werden an den nativen Button im Inneren weitergereicht (seit 1.20.0) — <glk-popover> setzt aria-expanded an seinem Trigger.

Formular-Komponenten

Alle Formular-Komponenten unterstützen name, value, disabled und nehmen an der nativen <form>-Übermittlung teil.

<glk-input>

Textfeld mit Label, Hinweis und Fehlerzustand.

EUR
<glk-input label="Email" type="email" placeholder="you@example.com" hint="Required" error name="email"></glk-input>
AttributeTypeDescription
labelStringInput label
typeStringtext, email, password, ...
placeholderStringPlaceholder text
hintStringHilfetext, als Beschreibung des Feldes vorgelesen
errorBooleanFehlerdarstellung; markiert das Feld für Screenreader als ungültig (aria-invalid, seit 1.20.0). Blockiert das Formular nicht — so kommt das Urteil eines Servers an
requiredBooleanPflichtfeld; solange es leer ist, sendet das Formular nicht (seit 1.20.0)
readonlyBooleanNur lesbar: fokussierbar, markierbar und wird abgeschickt, aber nicht editierbar; Property readOnly (seit 1.22.0)
min, max, stepStringAn das innere Feld durchgereicht: Bereich und Schrittweite des Pickers für Datum, Zeit und Zahlen (seit 1.17.0)
minlength, maxlength, patternStringAn das innere Feld durchgereicht (seit 1.17.0)
autocomplete, inputmodeStringAutofill und Bildschirmtastatur, an das innere Feld durchgereicht (seit 1.17.0)

Events: glk-input, glk-change

Slots (seit 1.22.0): prefix und suffix setzen ein Icon, eine Währung, eine Einheit oder einen Button in den Kasten des Feldes, an seinen Anfang und sein Ende — von rechts nach links tauschen sie die Seiten. Jeder erscheint nur, solange etwas darin steckt; seine Breite wird gemessen, und der Text hält Abstand. Ein Klick auf Text, ein Icon oder ein deaktiviertes Bedienelement im Slot geht durch ins Feld; aktive Bedienelemente, <glk-button> und <glk-select> eingeschlossen, Links und Elemente mit tabindex nehmen ihren eigenen (seit 1.22.2 — vorher nahm jedes Element im Slot den Klick). Das Bedienelement selbst in den Slot setzen: steckt es in einem anderen Element, braucht es pointer-events: auto von der Seite. Ein Container, der mit pointer-events: none sperrt, hält ein Bedienelement nicht; ihn mit inert sperren oder das Bedienelement deaktivieren. Ihr Text wird als Beschreibung des Feldes vorgelesen. Der Kasten ist der Part box, die Affixe sind prefix und suffix.

<glk-input label="Preis" inputmode="decimal"> <span slot="suffix">EUR</span> </glk-input>

<glk-textarea>

<glk-textarea label="Message" rows="4"></glk-textarea>

Attribute: label, rows, placeholder, required, readonly (seit 1.22.0), name, value, disabled. Das Label benennt das Feld.

<glk-select>

<glk-select label="Plan" name="plan"> <option value="free">Free</option> <option value="pro">Pro</option> </glk-select>

Kinder: native <option>-Elemente. Mit required und einer leeren ersten Option (value="") sendet das Formular erst, wenn gewählt wurde (seit 1.20.0). Das Label benennt das Feld. Ein value — als Attribut oder Property —, für den es noch keine Option gibt, bleibt erhalten und wird gewählt, sobald seine Option kommt, bis der Nutzer etwas anderes wählt (seit 1.22.0; vorher ging ein als Property gesetzter Wert verloren, wenn die Optionen noch nicht kopiert waren). Ein Formular-Reset kehrt zum value-Attribut zurück.

<glk-toggle>

Schalter-Toggle mit Formular-Teilnahme.

<glk-toggle label="Notifications" name="notify" checked></glk-toggle>
AttributeTypeDescription
labelStringToggle label
checkedBooleanChecked state
disabledBooleanDisabled state
requiredBooleanMuss an sein, bevor das Formular sendet (seit 1.20.0)

Events: glk-change → { checked: boolean }

Der Schalter ist die native Checkbox im Inneren, mit role="switch": ein Bedienelement für Screenreader, benannt durch label, sein Zustand kommt von der Checkbox. Seit 1.20.0 trägt das Element selbst kein role, aria-checked oder aria-disabled mehr — Styles und Selektoren auf [checked] und [disabled]. element.click() und ein <label> um das Element oder mit Verweis darauf schalten es um, wie bei einer nativen Checkbox; das gilt auch für <glk-checkbox> und <glk-radio>. Ohne label ist das Element genau so groß wie seine Spur, 52 × 30 px.

<glk-checkbox>

<glk-checkbox label="I agree" name="terms" checked></glk-checkbox>

required hält das Formular vom Absenden ab, bis das Kästchen angehakt ist (seit 1.20.0).

<glk-radio>

<glk-radio name="plan" label="Free" value="free" checked></glk-radio> <glk-radio name="plan" label="Pro" value="pro"></glk-radio>

required an einem Radio der Gruppe macht die Gruppe zur Pflicht; jedes gewählte Radio erfüllt sie, wie bei nativen Radios (seit 1.20.0).

<glk-range>

<glk-range label="Volume" min="0" max="100" value="65"></glk-range>
AttributeTypeDescription
minNumberMinimum (default: 0)
maxNumberMaximum (default: 100)
valueNumberCurrent value
stepNumberStep increment

<glk-segmented>

Eine kleine, exklusive Auswahl als ein Bedienelement. Rendert je Option einen <button>, der gewählte trägt aria-pressed="true"; eine Wertänderung setzt nur dieses Attribut neu, der Fokus bleibt, wo er war. Formular-assoziiert: ein umschließendes <form> erhält name=value, Reset stellt den Anfangswert wieder her. Probier es: Tab auf einen Knopf, Leertaste. Mehr Optionen als Platz: overflow="scroll" hält eine Zeile, die seitwärts scrollt, und die gewählte Option im Blick, overflow="wrap" bricht sie um.

wartet auf glk-change…
<glk-segmented full label="Status" name="status" value="y" options='[{"value":"g","label":"Grün","tone":"success"}, {"value":"y","label":"Gelb","tone":"warning"}, {"value":"x","label":"Gesperrt","disabled":true}]'></glk-segmented>
AttributTypWerte
optionsJSON[{ value, label, tone?, disabled? }] — tone: success | warning | error
valueStringWert der gewählten Option
fullBooleanKnöpfe teilen sich die Breite
overflowStringscroll — eine Zeile, die seitwärts scrollt, die gewählte Option bleibt im Blick; wrap — bricht um. Ohne bleibt die Zeile einzeilig (seit 1.17.0)
labelStringaria-label der Gruppe
nameStringFeldname im Formular (form-assoziiert)
disabledBooleanDie ganze Reihe (seit 1.22.3); ein <fieldset disabled> um sie herum deaktiviert sie ebenso

Events: glk-change { value } — nur bei einer Änderung durch den Nutzer. Part: group.

<glk-calendar>

Ein Monat mit einem Tag zum Wählen. Die Tage sind Knöpfe in einer role="group", der gewählte trägt aria-pressed="true", jeder ist mit seinem vollen Datum benannt; Monatstitel, Wochentagsnamen und der erste Wochentag kommen aus Intl für die locale (week-start übersteuert). Ein Tab-Stopp: Pfeiltasten wandern um einen Tag oder eine Woche, Pos1/Ende an die Enden der Woche, Bild auf/ab um einen Monat — über die Monatsgrenze hinaus zeigt der Kalender diesen Monat und sendet glk-month. Pfeiltasten bewegen nur den Fokus; Enter oder Leertaste wählt, damit ein Kalender, der bei jeder Wahl ein Sheet öffnet, beim Umschauen still bleibt. Tage außerhalb von min/max sind aria-disabled: im Pfeilpfad, angesagt, nie gewählt. Formularfähig wie <glk-segmented>. Probier es: Mit Tab ins Raster, Pfeiltasten, Enter.

wartet auf glk-change / glk-month…
<glk-calendar name="day" value="2026-09-22" min="2026-09-22" label="Tag wählen" marks='{"2026-09-24":["error"],"2026-09-27":["success","warning"]}'></glk-calendar>
AttributTypWerte
monthStringGezeigter Monat YYYY-MM; ohne Angabe der Monat des Werts, sonst von heute. Wird beim Blättern reflektiert; ein Wert in einem anderen Monat schaltet dorthin um
valueStringGewählter Tag YYYY-MM-DD
todayStringDer Tag mit dem warmen Rahmen; ohne Angabe der Tag des Browsers
min, maxStringTage außerhalb sind nicht wählbar (aria-disabled)
marksJSON{ "2026-09-30": ["error", "warning"] } — bis zu drei Töne je Tag: primary | success | warning | error
localeStringBCP-47-Tag für Namen und Wochenbeginn; ohne Angabe die Sprache der Seite — das lang des nächsten Vorfahren, meist <html lang>, auch über Shadow Roots hinweg —, sonst die Browsersprache (Seitensprache seit 1.19.2)
week-startNumber0 = Sonntag … 6 = Samstag; ohne Angabe aus der Locale, Montag wo der Browser es nicht weiß
labelStringaria-label der Tagesgruppe
prev-label, next-labelStringNamen der Navigationsknöpfe; Vorgabe „Previous month“ / „Next month“
nameStringFeldname im Formular (formularfähig)
disabledBooleanPfeile und Tage (seit 1.22.3); ein <fieldset disabled> um ihn herum deaktiviert ihn ebenso

Ereignisse: glk-change { value } bei einer Wahl durch den Nutzer; glk-month { month } wenn der Nutzer zu einem anderen Monat wechselt. Eigenschaften: month, value, marks, locale, label, disabled. Parts: calendar, head, title, grid.

<glk-image-picker>

Ein Bild mit Vorschau, auf dem Client verkleinert, bevor es irgendwohin geht. Auswählen öffnet den Dateidialog aus einem echten Knopf; die Datei wird mit createImageBitmap dekodiert, die EXIF-Drehung eines Handyfotos angewendet, auf ein Canvas nicht größer als max gezeichnet und als Data-URL in glk-change übergeben. Die Eigenschaft src hält sie und wird nicht reflektiert, damit eine Data-URL von Megabytes nie im DOM landet. Eine Datei, die der Browser nicht dekodieren kann — Chrome und HEIC, eine kaputte Datei — sendet glk-error, statt still zu scheitern. Nicht formularfähig: auf glk-change hören und hochladen. Probier es mit einem Foto vom Handy.

wartet auf glk-change…
<glk-image-picker round max="512" label="Profilfoto" hint="JPG, PNG"></glk-image-picker> <script>picker.addEventListener('glk-change', e => upload(e.detail.dataUrl));</script>
AttributTypWerte
srcStringStartbild: URL oder Data-URL
labelStringSichtbare Beschriftung; benennt die Gruppe
hintStringKleine gedämpfte Zeile; ohne Vorgabe — was angenommen wird, hängt von accept und vom Browser ab
roundBooleanRunde Vorschau, für Avatare
maxNumberLängste Kante in px nach dem Verkleinern, Vorgabe 1024
type, qualityString, NumberAusgabe-MIME (Vorgabe image/jpeg; image/webp, wo der Browser es kodiert, sonst PNG) und Qualität 0–1 (Vorgabe 0,82)
acceptStringFilter des Dateidialogs, Vorgabe image/*
choose-label, change-label, remove-labelStringKnopftexte; Vorgabe „Choose“, „Change“, „Remove“

Ereignisse: glk-change { dataUrl, width, height, size } nach einer Wahl, beim Entfernen mit leerer dataUrl und Nullen; glk-error { message, name } wenn die Datei nicht dekodiert werden kann. Eigenschaft: src (nicht reflektiert). Parts: picker, preview, meta, label, hint, actions.

Navigation

<glk-nav> + <glk-pill>

Horizontale Navigationsleiste mit runden Icon-Buttons.

<glk-nav> <glk-pill label="Back"><svg>...</svg></glk-pill> <glk-pill label="Settings"><svg>...</svg></glk-pill> </glk-nav>

<glk-tab-bar> + <glk-tab-item>

Tab-Leiste fuer die Navigation am unteren Bildschirmrand.

<glk-tab-bar> <glk-tab-item label="Home" active><svg>...</svg></glk-tab-item> <glk-tab-item label="Profile" badge="3"><svg>...</svg></glk-tab-item> </glk-tab-bar>
AttributeComponentDescription
labelglk-tab-itemTab label
activeglk-tab-itemActive state
badgeglk-tab-itemBadge count

Events: glk-tab-change → { tab: Element }

<glk-tab-dock> + <glk-tab-bar floating> + <glk-tab-accessory>

Pillenfoermige, mittig schwebende Tab-Leiste im Stil von iOS 26 Liquid Glass. Optional kombinierbar mit einer <glk-tab-accessory>-Kapsel (z.B. Suche, Verfassen). Der aktive Tab erhaelt einen weichen radialen Spotlight-Halo statt der Unterstrich-Markierung. Verwende .glass-bg--has-tab-bar-floating auf dem aeusseren Hintergrund.

<glk-tab-dock> <glk-tab-bar floating> <glk-tab-item label="Home" active><svg>...</svg></glk-tab-item> <!-- weitere Items --> </glk-tab-bar> <glk-tab-accessory variant="accent" label="Verfassen"> <svg>...</svg> </glk-tab-accessory> </glk-tab-dock>
AttributKomponenteBeschreibung
floatingglk-tab-barPillenfoermige Liquid-Glass-Variante — Spotlight-Halo am aktiven Item
accessory-leftglk-tab-dockAccessory links statt rechts neben der Bar
labelglk-tab-accessoryaria-label fuer Barrierefreiheit
variantglk-tab-accessoryaccent | success | error — gefuellte farbige Kapsel mit weissem Icon
disabledglk-tab-accessoryDeaktiviert

Events: <glk-tab-accessory> sendet glk-click beim Klick (unterdrueckt im disabled-Zustand).

Tipp: Nutze .glass-bg--has-tab-bar-floating auf dem aeusseren .glass-bg statt --has-tab-bar, damit das Padding zur schwebenden Variante passt.

<glk-steps>

Fortschritt durch einen kurzen Ablauf, rein darstellend: der aktuelle Schritt trägt aria-current="step", erledigte zeigen einen SVG-Haken. Die Verengung in schmalen Rahmen macht die Container-Query des CSS-Blocks (unter 360 px bleibt nur das aktuelle Label) — das Element weiß nichts davon.

<glk-steps steps="Tag,Fenster,Hund,Bestätigen" current="2"></glk-steps>
AttributTypWerte
stepsStringKommagetrennte Beschriftungen
currentNumber0-basierter Index des aktuellen Schritts
labelStringaria-label der Liste (optional)

Eigenschaft current spiegelt das Attribut; steps nimmt ein Array oder kommagetrennten Text. Part: steps.

<glk-date-strip>

Eine Reihe von Tages-Chips, die seitwärts scrollt — ein Buchungshorizont, die Tage um heute. Die Chips sind Knöpfe in einer role="group", der gewählte trägt aria-pressed="true", jeder ist mit seinem vollen Datum benannt. Ein Tab-Stopp: Pfeiltasten wandern zwischen den Chips, Pos1/Ende springen an die Enden, Enter oder Leertaste wählt. Der gewählte Chip wird nach dem ersten Layout und bei jeder Wertänderung in die Mitte des Streifens gescrollt — nur der Streifen scrollt, nie die Seite. Wochentagsnamen kommen aus Intl für die locale. Probier es: Der Streifen unten beginnt mit dem 20. Tag gewählt.

wartet auf glk-change…
<glk-date-strip start="2026-09-22" days="29" value="2026-10-11" label="Tag wählen" marks='{"2026-09-22":"success","2026-09-25":{"tone":"error","disabled":true}}'></glk-date-strip>
AttributTypWerte
startStringErster Tag YYYY-MM-DD; ohne Angabe heute
daysNumberAnzahl der Chips, Vorgabe 7
valueStringGewählter Tag YYYY-MM-DD
todayStringDer unterstrichene Tag; ohne Angabe der Tag des Browsers
marksJSON{ "2026-09-24": "warning", "2026-09-25": { "tone": "error", "disabled": true } } — tone: primary | success | warning | error; disabled macht den Chip unwählbar
localeStringBCP-47-Tag für Wochentagsnamen und das aria-label der Chips; ohne Angabe die Sprache der Seite — das lang des nächsten Vorfahren, meist <html lang>, auch über Shadow Roots hinweg —, sonst die Browsersprache (Seitensprache seit 1.19.2)
labelStringaria-label der Gruppe

Ereignisse: glk-change { value } — nur bei einer Änderung durch den Nutzer. Eigenschaften: value, marks (Objekt oder JSON-Text), locale, label. Part: strip.

Feedback

<glk-progress>

<glk-progress label="Upload" value="75" variant="success"></glk-progress>
AttributeTypeValues
valueNumber0 – 100
variantStringsuccess | error
sizeStringsm | (default) | lg

<glk-modal>

Modaler Dialog mit Titel, Inhalt und Aktions-Buttons. Seit 1.20.0 ist er ein natives <dialog>, geöffnet mit showModal(): Er liegt über allem anderen, die Seite dahinter ist für Zeiger, Tastatur und Screenreader inert, der Fokus wandert hinein und beim Schließen dorthin zurück, wo er herkam, und der Inhalt ist außer Reichweite, solange er geschlossen ist. Der Titel benennt den Dialog.

Modal oeffnen

Sind Sie sicher, dass Sie fortfahren moechten?

<glk-modal title="Confirm" id="my-modal"> <p>Are you sure?</p> <div slot="actions"> <button class="glass-modal__action">Cancel</button> <button class="glass-modal__action glass-modal__action--primary">OK</button> </div> </glk-modal> // Methods document.getElementById('my-modal').show(); document.getElementById('my-modal').close();
AttributeTypeDescription
openBooleanShow/hide
titleStringHeader title

Methods: .show(), .close()   Events: glk-close

Welches Element beim Öffnen den Fokus bekommt, entscheiden die Browser verschieden — Chrome nimmt das erste Feld des Inhalts, Safari die erste Aktion. Ein autofocus im Inhalt oder an einer Aktion legt es fest. Escape und ein Klick auf die abgedunkelte Fläche schließen das Modal mit Blende und senden glk-close; .close() sendet nichts. Solange es offen ist, ist alles außerhalb inert — ein <glk-toast>, der dann erscheint, ist weder anklickbar noch wird er vorgelesen. Rückmeldungen gehören deshalb ins Modal, oder es schließt zuerst.

<glk-toast>

Benachrichtigung am oberen Rand, die sich selbst ausblendet — und seit 1.19.0 eine, die etwas anbietet: Mit action-label (oder show(message, { action })) bekommt sie einen Knopf und ein × und bleibt stehen, bis eines davon benutzt wird, es sei denn, eine Dauer ist gesetzt. Die Aktion sendet glk-action und schließt den Toast — außer ein Listener ruft preventDefault() auf oder zeigt die nächste Nachricht; × und Escape senden glk-close. Solange Zeiger oder Fokus darauf liegen, läuft er nicht ab. Er ist eine höfliche Live-Region, die Nachricht wird also angesagt.

Erfolg Fehler Mit Aktion wartet auf glk-action / glk-close…
<glk-toast id="toast"></glk-toast> // Show programmatically document.getElementById('toast').show('Saved!', 'success', 3000); // With an action: stays until Reload or × is used toast.show('Neue Version verfügbar', { action: { label: 'Neu laden', value: 'reload' } }); toast.addEventListener('glk-action', e => { if (e.detail.action === 'reload') location.reload(); });
AttributeTypeValues
messageStringDer Text
variantStringsuccess | error | warning — färbt Symbol und Aktion
durationNumberms; 0 hält ihn stehen. Vorgabe 3000 — mit Aktion kein Ablauf, außer gesetzt
visibleBooleanSichtbar
action-label, action-valueStringDer Aktionsknopf und der Wert, den glk-action meldet (ohne Angabe die Beschriftung) (seit 1.19.0)
dismissibleBooleanEin × ohne Aktion; eine Aktion bringt immer eins mit (seit 1.19.0)
close-labelStringName des ×, Vorgabe „Close“ (seit 1.19.0)

Methoden: .show(message, variant, duration), .show(message, { variant, duration, action: { label, value }, dismissible }), .dismiss(). Slot: icon — ersetzt das eingebaute Symbol; ohne eigenen Stroke nimmt es die Variantenfarbe an. Ereignisse: glk-action { action, label } (abbrechbar), glk-close (× oder Escape), glk-dismiss (abgelaufen).

<glk-popover>

Anchored Dropdown- / Menü-Container. Wrappt ein Trigger-Element (via slot="trigger") und dessen Floating-Inhalt. Das Element verwaltet .is-open-Toggle, Outside-Click-Dismiss und Escape-Key-Close intern — kein manuelles Klassen-Umschalten nötig.

Menü öffnen
<glk-popover placement="end"> <glk-button slot="trigger" variant="secondary">Menü öffnen</glk-button> <glk-list bare> <glk-list-item title="Teilen" interactive></glk-list-item> <glk-list-item title="Löschen" variant="danger" interactive></glk-list-item> </glk-list> </glk-popover> // Imperative API document.querySelector('glk-popover').show(); document.querySelector('glk-popover').close(); document.querySelector('glk-popover').toggle();
AttributeTypDefaultBeschreibung
openBooleanfalseSichtbarkeitsstatus (wird als .is-open auf die innere Fläche gespiegelt)
placementStringbottomtop | bottom | start | end
SlotZweck
triggerElement, das den Popover beim Klick toggelt
(default)Floating-Inhalt, der im offenen Zustand angezeigt wird

Events: glk-open, glk-close

Methoden: .show(), .close(), .toggle()

Achtung: die Methode heißt bewusst .toggle() — nicht .togglePopover(), da dies mit der nativen HTMLElement.togglePopover()-API kollidiert.

Der Trigger sagt, ob der Popover offen ist: Er bekommt aria-expanded, auch nachdem er ausgetauscht wurde (seit 1.20.0). <glk-button> und <glk-pill> reichen es an ihren nativen Button weiter.

<glk-sheet>

Bottom-Sheet — das mobile Geschwister von <glk-modal>. Öffnen und Schließen animiert GlassKits .glass-sheet-Block; das Overlay wird erst nach transitionend versteckt, damit keine Blur-Schicht hinter der Seite stehen bleibt, und unter prefers-reduced-motion schaltet es sofort. Scrim-Klick und Escape schließen und senden glk-close; show() / close() nicht. inline bettet das Panel ohne Overlay ein.

Inhalt des Sheets: Liste, Text, Formular. Dieses hier ist eingebettet.

Als Overlay öffnen

Tippen außerhalb oder Escape schließt.

Schließen
<glk-sheet id="sheet" title="Umbuchen auf …"> <p>…</p> <glk-button slot="actions" onclick="sheet.close()">Schließen</glk-button> </glk-sheet> <script>sheet.show();</script>
AttributTypWerte
openBooleanAls Overlay angezeigt
inlineBooleanIm Fluss, ohne Overlay, immer sichtbar
titleStringÜberschrift und aria-label

Methoden: show(), close(). Slots: Standard (Inhalt), actions. Events: glk-close — nur beim Schließen durch den Nutzer (Scrim, Escape). Parts: overlay, sheet, title, body, actions.

Container

<glk-accordion> + <glk-accordion-item>

Einklappbare Akkordeon-Abschnitte.

Content for section 1. Content for section 2.
<glk-accordion> <glk-accordion-item title="FAQ" open> Answer here. </glk-accordion-item> </glk-accordion>
AttributeComponentDescription
titleglk-accordion-itemTrigger text
openglk-accordion-itemExpanded state

Events: glk-toggle → { open: boolean }

Der Trigger trägt aria-expanded und aria-controls; ein geschlossener Abschnitt ist inert, seine Links und Felder sind also aus der Tab-Reihenfolge und aus dem Accessibility-Baum, bis er sich öffnet (seit 1.20.0).

<glk-list> + <glk-list-item>

iOS-Style gruppierte Einstellungsliste. Items tragen ein führendes Icon, Titel + optionalen Untertitel und ein nachgelagertes Element. Divider zwischen den Items werden automatisch gezeichnet — niemals <hr>-Markup zwischen Items einfügen. Unterstützt Sektions-Header, große Icons, mehrzeilige Untertitel, Trailing-Werte und semantische Varianten.

<glk-list header="Empfehlungen"> <glk-list-item title="Medien prüfen" subtitle="Bis zu 1,38 GB." leading-lg wrap interactive> <svg slot="leading">...</svg> <svg slot="trailing">...</svg> </glk-list-item> <glk-list-item title="App" leading-lg detail="24 MB" interactive>...</glk-list-item> <glk-list-item title="Löschen" variant="danger" center interactive></glk-list-item> <glk-list-item title="Alle anzeigen" variant="accent" center interactive></glk-list-item> </glk-list>
AttributeKomponenteBeschreibung
headerglk-listSektions-Header — Großbuchstaben-Label über der Liste
flushglk-listEdge-to-Edge-Variante — entfernt seitlichen Rand und Radius
bareglk-listEntfernt Hintergrund, Border, Shadow — für Einbettung in <glk-popover> oder <glk-card>
titleglk-list-itemHaupttext
subtitleglk-list-itemSekundärtext (muted, optional)
interactiveglk-list-itemHover- / Focus- / Active-States + feuert glk-click
centerglk-list-itemZentrierte Single-Text-Variante (z.B. für Aktionszeilen)
leading-lgglk-list-itemGroßes 40×40 Leading-Icon mit abgerundeten Ecken (für App-Icons)
wrapglk-list-itemMehrzeiliger Untertitel (bis 3 Zeilen mit Ellipsis)
detailglk-list-itemMuted Trailing-Wert (z.B. Dateigröße, Version)
variantglk-list-itemdanger (rote Destruktiv-Aktion) oder accent (Primärfarbe)
SlotKomponenteZweck
leadingglk-list-itemIcon-Slot (24×24 SVG, oder 32×32 mit leading-lg)
trailingglk-list-itemChevron, Badge oder Button (gerendert nach detail-Wert)

Events: glk-click auf <glk-list-item>, sobald interactive gesetzt ist.

Framework-sicher: beide Elemente nutzen pures Shadow DOM mit Slot-Projection — kein Clonen von Kinder-Knoten — und komponieren sauber in lit-html-Templates, HybridsJS, React, Vue und Svelte.

Eigene Elemente bauen

Seit 1.14.0 sind die Basisklassen exportiert. Ein Projekt-Element, das GlkElement erweitert, bekommt, was jedes <glk-*> hat: einen offenen Shadow Root mit adoptiertem GlassKit-Stylesheet (.glass-btn & Co. funktionieren darin), den Theme-Wrapper, der data-theme und data-density folgt, beim Verschieben neu gesetzte Listener und emit() für bubbling, composed Events. GlkFormElement ergänzt ElementInternals für native Formularteilnahme. Probier es aus — dieser Knopf ist ein auf dieser Seite definiertes <demo-counter>:

wartet auf demo-count…
import { GlkElement } from '@jungherz-de/glasskit-elements'; class DemoCounter extends GlkElement { static get observedAttributes() { return ['count']; } render() { // this._wrapper ist die Theme-Wurzel; GlassKit-Klassen funktionieren darin this._btn = this.createElement('button', ['glass-btn', 'glass-btn--secondary', 'glass-btn--sm', 'glass-btn--auto']); this._wrapper.appendChild(this._btn); } setupEvents() { this._onClick = () => { this.count += 1; this.emit('demo-count', { count: this.count }); }; this._btn.addEventListener('click', this._onClick); } teardownEvents() { this._btn?.removeEventListener('click', this._onClick); } onAttributeChanged() { /* Beschriftung neu setzen */ } get count() { return Number(this.getAttribute('count')) || 0; } set count(v) { this.setAttribute('count', v); } } customElements.define('demo-counter', DemoCounter);
SetupImport
Bundle (ESM)import { GlkElement, GlkFormElement } from '@jungherz-de/glasskit-elements';
Pro Komponenteimport { GlkElement } from '@jungherz-de/glasskit-elements/base.js'; — genau das Modul, das die Komponenten importieren, also gilt instanceof GlkElement über beide hinweg. Die Einzelmodule lassen @jungherz-de/glasskit/glasskit-styles.js extern: ein Bundler löst es auf, eine Import-Map braucht einen Eintrag dafür. Nie neben dem <script>-Bundle — das trägt seine eigene Kopie der Klasse.
CDN / <script>const { GlkElement } = GlassKitElements;

Hooks: render() baut in this._wrapper; setupEvents() / teardownEvents() laufen bei jedem Connect / Disconnect; onAttributeChanged(name, old, value) feuert nach dem ersten Render. Helfer: createElement(tag, classes, attrs), getBoolAttr() / setBoolAttr(), emit(name, detail). static get displayInline() liefert true für ein Inline-Element; static get observesLightDom() lässt projectLightDom() bei jeder Änderung der Light-DOM-Kinder erneut laufen. Seit 1.20.0 gibt static get delegatesFocus() mit true den Fokus an das erste Feld im Inneren weiter (an für GlkFormElement), und ein GlkFormElement, dessen get _validityField() sein natives Feld liefert, meldet dessen Gültigkeit am Host — nach jedem setFormValue() und jeder Attributänderung. Seit 1.22.3 gibt applyDisabled(disabled) den Deaktiviert-Zustand an die nativen Bedienelemente weiter: in einem GlkFormElement überschreiben. Es läuft nach dem ersten Render und immer dann, wenn sich das eigene disabled des Elements oder ein <fieldset disabled> um es herum ändert — von selbst reicht kein Fieldset in den Shadow Root.

Eine komplette Website bauen?

GlassKit Elements ist die App-Schicht der GlassKit-Familie – Web Components für Anwendungs-UIs. Für komplette Marketing-Websites – Sektionen, i18n, SEO – ist GlassKit Web der vorgesehene Weg: das offizielle Astro-Template auf derselben Designsprache. Das Pure-CSS-Fundament unter beiden ist GlassKit.