πŸ‡©πŸ‡ͺ DE

Glassmorphism UI Library

A complete CSS component library with glassmorphism aesthetics – built by Jungherz GmbH. Pure CSS, no dependencies, Dark & Light mode.

v1.22.2 CSS only Dark + Light 34 Components

Installation

Include one CSS file – done. Optionally add a theme override for custom brand colors.

<!-- Base Library --> <link rel="stylesheet" href="glasskit.css"> <!-- Optional: Theme Override --> <link rel="stylesheet" href="theme-override.css"> <!-- Dark Mode (Default) --> <html data-theme="dark"> <!-- Light Mode --> <html data-theme="light">

Design Tokens

All visual values are controlled via CSS Custom Properties.

Color Palette

TokenDark ValueUsage
--gl-color-primary#f5a623Primary color, buttons, active elements
--gl-color-primary-dark#d4692aGradient end value
--gl-color-text#ffffffDefault text color
--gl-color-text-mutedrgba(255,255,255,0.60)Secondary text
--gl-color-success#34c759Success status
--gl-color-error#ff3b30Error status
--gl-color-warning#ffcc00Warning status
--gl-color-{state}-surface, -border, -on-surfacecolor-mix(…)Tinted fill, border and text of a state badge, derived from the state colour — for success, error and, since 1.18.0, warning

Glass Surfaces

TokenValueUsage
--gl-surface-1rgba(…, 0.08)Subtlest surface (status)
--gl-surface-2rgba(…, 0.10)Default (inputs, cards)
--gl-surface-3rgba(…, 0.14)Nav pills, badges
--gl-surface-4rgba(…, 0.16)Hover states
--gl-surface-5rgba(…, 0.22)Strong hover
--gl-surface-milk-strongrgba(…, 0.75)Secondary button

Spacing & Radii

TokenValueTokenValue
--gl-space-2xs4px--gl-radius-xs8px
--gl-space-xs8px--gl-radius-sm12px
--gl-space-sm12px--gl-radius-input14px
--gl-space-md16px--gl-radius-btn16px
--gl-space-lg20px--gl-radius-card24px
--gl-space-xl24px--gl-radius-full9999px
--gl-space-2xl32px--gl-radius-pill50%

Density

TokenDefaultCompactUsage
--gl-control-height52px40pxInput, select, search
--gl-control-padding-xunset → --gl-space-md--gl-space-smInner left/right padding of input, select, textarea
--gl-btn-height56px40pxButton
--gl-btn-height-sm44px32pxButton --sm
--gl-btn-height-lg64px48pxButton --lg
--gl-textarea-min-height120px88pxTextarea
--gl-list-item-min-height56px48pxList row
--gl-list-item-padding-yunset → --gl-space-md10pxList row, top and bottom
--gl-toggle-width × -height52 × 30px44 × 26pxToggle track
--gl-toggle-thumb-size22px18pxToggle thumb
--gl-check-size24px20pxCheckbox, radio
--gl-modal-action-height52px44pxModal actions

Theming (Light / Dark)

The theme is controlled via data-theme on the <html> element.

// Theme per JavaScript wechseln: function toggleTheme() { const html = document.documentElement; const current = html.getAttribute('data-theme'); html.setAttribute('data-theme', current === 'dark' ? 'light' : 'dark' ); }

Right to left

Since 1.20.0 the components follow the writing direction. Set dir="rtl" on <html> or on any container: paddings, insets and borders are logical properties, so labels and hints, the search icon, list dividers, popover anchors, tab badges, modal actions, the toast’s close button and the alignment of accordion, list, table and prose all mirror. Where two values have to move together — the select’s chevron and the room kept for it, the toggle’s thumb and its travel, the progress fill’s gradient — the rule sits under :dir(rtl): Chrome and Edge from 120, Safari from 16.4, Firefox from 49. An older browser keeps those parts left to right instead of tearing them apart.

Printing

Print dialogs leave out background graphics by default, and some states are drawn with a background only. Since 1.21.1 those parts keep their colours on paper — the checked box and its tick, the chosen radio, the toggle’s track, the progress fill, the current step, the chosen day of date strip and calendar, the slider thumb and the tone dots — while the rest of the page prints economically. Nothing to set. A dark page prints its light text and surfaces on white paper; a page meant for printing switches to the light theme for it:

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'); });

Density (Compact)

Admin screens, desktop layouts and narrow forms want denser controls. Since 1.21.0 the control sizes are density tokens, and data-density="compact" on the <html> element swaps in a smaller set: fields and buttons 40px high instead of 52 and 56, smaller toggles, checkboxes and radios, denser list rows and modal actions. Colours, type and spacing stay as they are. Without the attribute every control keeps the size it has always had.

Default
Compact

The preview sets the attribute on its right column. On a page it belongs on <html>, next to data-theme: an element further down that carries data-theme="dark" re-declares the default sizes.

<html data-theme="dark" data-density="compact"> // Switch at runtime: document.documentElement.setAttribute('data-density', 'compact'); document.documentElement.removeAttribute('data-density'); /* One token for both densities – or for compact only: */ :root { --gl-btn-height: 48px; } [data-density='compact'] { --gl-btn-height: 36px; }

The toggle's thumb inset and travel — in either writing direction — and the first-line alignment of toggle, checkbox and radio are derived from the tokens, so any size a project sets stays aligned. The rules read every size with today's value as fallback, like --gl-modal-max-width, so a page whose token sheet predates them keeps the old sizes.

Background

The glass effect requires a colored background.

ClassDescription
.glass-bgFull background with aurora light effects
.glass-bg--has-tab-barModifier: bottom padding for tab bar
.glass-bg--has-tab-bar-floatingModifier: bottom padding for floating tab bar + accessory
<div class="glass-bg glass-bg--has-tab-bar"> <!-- Inhalte --> </div>

Pill-Buttons

Round icon buttons for navigation and actions.

ClassDescription
.glass-pillStandard glass circle (46Γ—46px)
.glass-theme-togglePill with moon/sun icon switch

Tab-Bar

Fixed bottom navigation with glass background and optional badge.

<nav class="glass-tab-bar"> <button class="glass-tab-bar__item is-active"> <span class="glass-tab-bar__icon"><!-- SVG --></span> <span class="glass-tab-bar__label">Start</span> </button> <button class="glass-tab-bar__item"> <span class="glass-tab-bar__icon"> <!-- SVG --> <span class="glass-tab-bar__badge">3</span> </span> <span class="glass-tab-bar__label">Contracts</span> </button> </nav>

Tab-Bar – Floating

Pill-shaped, centered, floating variant inspired by iOS 26 Liquid Glass. Pair with an optional .glass-tab-bar__accessory capsule (e.g. search, compose) β€” sits next to the bar with its own glass material. The active tab gets a soft radial Spotlight halo instead of the underline dot.

<div class="glass-tab-bar-dock"> <nav class="glass-tab-bar glass-tab-bar--floating"> <button class="glass-tab-bar__item is-active"> <span class="glass-tab-bar__icon"><!-- SVG --></span> <span class="glass-tab-bar__label">Home</span> </button> <!-- more items --> </nav> <button class="glass-tab-bar__accessory" aria-label="Search"> <!-- SVG --> </button> </div>

Accessory accent variants

Add --accent, --success, or --error to highlight the accessory with a colored capsule (filled background, white icon).

ClassDescription
.glass-tab-bar-dockWrapper: fixed bottom-center, holds bar + accessory
.glass-tab-bar-dock--accessory-leftModifier: place accessory on the left
.glass-tab-bar--floatingModifier on .glass-tab-bar: pill shape, max-content width
.glass-tab-bar__accessoryStandalone glass capsule next to the bar
.glass-tab-bar__accessory--accentFilled with primary color
.glass-tab-bar__accessory--successFilled with success color
.glass-tab-bar__accessory--errorFilled with error color
.glass-bg--has-tab-bar-floatingBackground padding helper for the floating variant

Title

Capture Contracts
& Upload

<h1 class="glass-title">Seitentitel</h1>

Card

Photograph your document, verify edges, and upload in batch.

<div class="glass-card glass-card--glow"> <div class="glass-card__icon"><!-- SVG --></div> <p class="glass-card__text">Text</p> </div>
ClassDescription
.glass-cardBase glass surface
.glass-card--glowLight β†’ milky gradient + light streak
.glass-card__iconCentered icon wrapper
.glass-card__textDescription text

Buttons

ClassDescription
.glass-btnBase (56px, full width)
--primaryColored gradient
--secondaryMilky white
--tertiarySubtle glass
--sm44px height
--lg64px height
--autoAuto width
:disabled, [aria-disabled="true"]Dimmed to 0.45, not-allowed cursor, no hover (since 1.21.2)
svg.glass-icon--fillDeliberately filled icon (e.g. brand logos)

A disabled button — disabled, or aria-disabled="true" on an a.glass-btn, which cannot be disabled — is dimmed, shows the not-allowed cursor and no longer lifts on hover (since 1.21.2; before, it looked exactly like an enabled one). The link still navigates unless the page stops it. The same holds for pill, tab-bar accessory, modal actions, interactive list rows and the calendar’s month arrows; toggle, checkbox and radio dim their control and label, select, textarea and range dim like the input.

Badge

Standard Aktiv Fertig Offen Fehler
<span class="glass-badge glass-badge--primary">Aktiv</span>

Variants: --primary, --success, --warning (since 1.18.0) and --error. Each draws its fill, border and text from the state colour’s -surface, -border and -on-surface tokens, so re-colouring the state colour moves the whole badge.

Chips

A badge doubles as a filter chip. --interactive carries the affordance — pointer cursor, hover tint, focus ring — and --selected says which chip is on. Use a real <button> and put the state in aria-pressed, so the row works by keyboard and is announced as a toggle.

--selected deepens the colour the badge already carries instead of overruling it, so a status chip stays in its own colour when it is picked.

<button class="glass-badge glass-badge--interactive glass-badge--selected" aria-pressed="true">Active</button> <button class="glass-badge glass-badge--interactive" aria-pressed="false">Applied</button>
ClassDescription
--interactivePressable: cursor, hover tint, focus ring, press feedback
--selectedThe chip that is on — deepens the badge's own colour
--gl-badge-accentThe colour both states deepen. Set it per badge to give a chip a colour of its own.

Avatar

S
M
L
<div class="glass-avatar glass-avatar--lg">L</div>

Divider


<hr class="glass-divider">

Status Notice

No documents captured yet.

<div class="glass-status"> <svg viewBox="0 0 24 24"><!-- Icon --></svg> <p>No documents captured yet.</p> </div>

List

Grouped settings-style container for stacked rows. Items support a leading icon, title + optional subtitle, and a trailing element (chevron, value, button). Dividers between items are drawn automatically — no extra markup needed.

Settings style (icon + title + subtitle + trailing)

  • iOS 26.4 Update
    2.1 GB · Available now
  • Apple One
    Family — renews Apr 28
    $22.95
  • Notifications
  • View all subscriptions
<ul class="glass-list"> <li class="glass-list__item glass-list__item--interactive"> <span class="glass-list__leading"><svg>...</svg></span> <div class="glass-list__content"> <div class="glass-list__title">iOS 26.4 Update</div> <div class="glass-list__subtitle">2.1 GB · Available now</div> </div> <div class="glass-list__trailing"><svg>...</svg></div> </li> <!-- More items… dividers appear automatically --> <li class="glass-list__item glass-list__item--center">View all</li> </ul>

Compact menu (centered text, no icons)

  • Share document
  • Duplicate
  • Delete
<ul class="glass-list"> <li class="glass-list__item glass-list__item--center glass-list__item--interactive">Share document</li> <li class="glass-list__item glass-list__item--center glass-list__item--interactive">Duplicate</li> <li class="glass-list__item glass-list__item--center glass-list__item--interactive glass-list__item--danger">Delete</li> </ul>

Grouped sections with large icons

Recommendations
  • Review downloaded media
    Save up to 1.38 GB. Review all videos and audio files downloaded on your device and remove them as needed.
  • AusweisApp Bund
    Version 2.5.1
    24 MB
Audiobooks
  • Ghost in the Machine
    Partially watched
    237.1 MB
  • View all downloads
<div class="glass-list__section-header">Recommendations</div> <ul class="glass-list"> <li class="glass-list__item glass-list__item--interactive"> <span class="glass-list__leading glass-list__leading--lg"><svg>...</svg></span> <div class="glass-list__content"> <div class="glass-list__title">Review downloaded media</div> <div class="glass-list__subtitle glass-list__subtitle--wrap">Multi-line description...</div> </div> <div class="glass-list__trailing"> <span class="glass-list__value">24 MB</span> <svg>...</svg> </div> </li> <li class="glass-list__item glass-list__item--accent glass-list__item--center">View all</li> </ul>

Class reference

ClassDescription
.glass-listGrouped surface container
.glass-list--flushEdge-to-edge variant (no side margin / radius). Assumes parent has --gl-space-lg horizontal padding.
.glass-list--bareStrips background, border & shadow — for embedding inside .glass-popover or .glass-card.
.glass-list__itemList row (use <li>, <a>, or <button>)
.glass-list__section-headerSection label above a .glass-list — uppercase, small, muted
.glass-list__item--interactiveAdds hover / focus / active states
.glass-list__item--centerCentered single-text variant with ellipsis truncation
.glass-list__item--dangerRed text for destructive actions
.glass-list__item--accentPrimary-colored text for accent actions
.glass-list__leadingLeading slot (28×28, holds an icon SVG)
.glass-list__leading--lgLarge leading slot (40×40, rounded square, supports <img>)
.glass-list__contentFlexible middle slot — takes remaining width, enables truncation
.glass-list__titlePrimary text (medium weight, ellipsis)
.glass-list__subtitleSecondary text (small, muted, ellipsis)
.glass-list__subtitle--wrapMulti-line subtitle (up to 3 lines, clamped with ellipsis)
.glass-list__trailingTrailing slot — chevron, value, button, badge
.glass-list__valueMuted text inside .glass-list__trailing (e.g. file size)

Dividers between rows are rendered automatically via ::after. Items with a leading icon get an icon-aligned inset; items without — no __leading, or one carrying the hidden attribute (since 1.20.0) — get the standard padding inset. A hidden __leading or __trailing takes no room. The last item never has a divider. SVG icon convention: 24px for leading, 18px for trailing, stroke: currentColor, stroke-width: 2.

Toast

Visible via .is-visible. Variants: --success, --error, --warning.

With an action (since 1.19.0): __action is a small pill in the toast’s own tone — primary on a plain toast, the state colour on a variant — and __close the × at the end; give it an aria-label. Both have a 44 px hit area. A toast with an action may grow to 480 px, the text wraps, the buttons never shrink; it should stay until one of them is used. The toast sits --gl-toast-top from the top (56 px unless set) — set it below your header, and add env(safe-area-inset-top) with viewport-fit=cover. It stays at the top also with an action: one place for every toast.

Document uploaded successfully!
A new version is ready
<div class="glass-toast glass-toast--success"> <svg class="glass-toast__icon">...</svg> <span class="glass-toast__text">Success!</span> </div> <!-- with an action --> <div class="glass-toast is-visible" role="status"> <svg class="glass-toast__icon">...</svg> <span class="glass-toast__text">A new version is ready</span> <button class="glass-toast__action">Reload</button> <button class="glass-toast__close" aria-label="Close"><!-- Γ— SVG --></button> </div>
ClassDescription
.glass-toast, .is-visibleFixed at the top, faded in while visible
--success, --error, --warningColour the icon; tint the action in the state colour
__icon, __text22 px stroked icon, message (wraps and yields)
__actionOne action: pill in the toast’s tone, 44 px hit area, never shrinks (since 1.19.0)
__closeThe ×, 28 px with a 44 px hit area (since 1.19.0)
--gl-toast-topDistance from the top, default var(--gl-space-4xl) (since 1.19.0)

Popover

Anchored dropdown / menu container. Wrap a trigger and a .glass-popover in a .glass-popover-anchor. Visibility is controlled via the .is-open class — toggling it requires a tiny bit of JavaScript.

  • Share
  • Duplicate
  • Delete
<div class="glass-popover-anchor"> <button class="glass-btn glass-btn--secondary" onclick="togglePop(this)">Open menu</button> <div class="glass-popover"> <ul class="glass-list glass-list--bare"> <li class="glass-list__item glass-list__item--interactive">Share</li> <li class="glass-list__item glass-list__item--interactive">Delete</li> </ul> </div> </div> <script> // Note: do NOT name the function `togglePopover` — collides // with the native HTMLElement.togglePopover() API method. function togglePop(btn) { btn.nextElementSibling.classList.toggle('is-open'); } </script>

Class reference

ClassDescription
.glass-popover-anchorPositioning context for the popover (wraps trigger + popover)
.glass-popoverFloating glass surface, hidden until .is-open
.glass-popover.is-openVisible state — fade + scale animation
.glass-popover--topOpens upward (above the trigger)
.glass-popover--startAligns left edge with trigger
.glass-popover--endAligns right edge with trigger

Note: name your toggle function anything except togglePopover — that name collides with the native HTMLElement.togglePopover() method from the HTML Popover API and inline onclick handlers will throw a NotSupportedError.

Input

Please enter a valid email address
EUR

Date and time fields — type="date", time, datetime-local, month — take the same class. They drop the native appearance (since 1.17.0): iOS drew them wider than their column, an empty one narrower than a filled one, with the value centred. Now they sit in their column like every other field, the value at the start; the native picker still opens.

<div class="glass-input-group"> <label class="glass-label">Label</label> <input class="glass-input" type="text"> <span class="glass-hint">Help text</span> </div>

Prefix and suffix

An icon, a currency, a unit or a button inside the field’s box (since 1.22.0): wrap the input in .glass-input-wrap and put __prefix and __suffix next to it. They lie on the field, centred, at its start and end — right to left they swap sides. The field’s padding grows by their width, --gl-input-prefix-size and --gl-input-suffix-size: 18px, an icon, unless set — set it for a wider unit. It follows the --prefix / --suffix modifier, or a visible affix where :has() is supported. A click on text, an icon or a disabled control reaches the field; enabled controls, links and elements with tabindex take their own, form-associated custom elements such as <glk-button> included (since 1.22.2). They take it even inside a container locked with pointer-events: none: lock it with inert, or disable them. <glk-input> in GlassKit Elements has prefix and suffix slots on this and measures the width itself.

<div class="glass-input-wrap glass-input-wrap--suffix" style="--gl-input-suffix-size: 30px"> <input class="glass-input" inputmode="decimal"> <span class="glass-input-wrap__suffix">EUR</span> </div>

Textarea

<textarea class="glass-textarea"></textarea>

Select

<select class="glass-select"> <option>Please select…</option> </select>

The chevron is --gl-select-chevron, an SVG drawn in each theme’s muted text colour — since 1.20.0; before, it stayed white in the light theme and all but vanished. Set the token to your own url(…) to replace it. Right to left, the chevron and the room kept for it move to the left.

Toggle Switch

<label class="glass-toggle"> <input class="glass-toggle__input" type="checkbox"> <span class="glass-toggle__track"> <span class="glass-toggle__thumb"></span> </span> <span class="glass-toggle__label">Label</span> </label>

The input is invisible, but it lies on top of the track and takes the click itself (since 1.20.0): a test tool that clicks the switch by its role reaches it, where the track used to draw over it and take the click. It covers the track only — the label text, which may hold a link, stays the label’s. A __label left empty takes no room, so a switch without text keeps no 12 px gap for one. Both hold for the checkbox and the radio button too. Right to left, the thumb starts on the right.

Checkbox

As with the toggle, the input lies on top of the box and an empty __label takes no room (since 1.20.0).

Radio Button

As with the toggle, the input lies on top of the circle and an empty __label takes no room (since 1.20.0).

Range Slider

75%

Progress Bar

Standard68%
Success100%
ClassDescription
.glass-progressBase container
--sm / --lgTrack height: 4px / 12px
--success / --errorColor variants

Accordion

The detailed answer to this question.
The answer to question two.

Skeleton

Loading placeholder: shimmer lines standing in for text that has not arrived. Set each line's width; the shimmer follows the theme and holds still under prefers-reduced-motion. Mark the region aria-busy="true" so assistive tech knows it is loading.

<div class="glass-skeleton" aria-busy="true"> <div class="glass-skeleton__line glass-skeleton__line--title" style="width:55%"></div> <div class="glass-skeleton__line"></div> <div class="glass-skeleton__line" style="width:80%"></div> </div>
ClassDescription
.glass-skeletonStack of lines, 10px apart
.glass-skeleton__lineOne shimmer line (12px); width via inline style
.glass-skeleton__line--titleTaller line (18px) standing in for a heading

Table

A plain <table> on glass: hairline rows, a muted header, numbers right-aligned in tabular figures. The .glass-table-wrap wrapper scrolls sideways where the columns do not fit. Put the class on the table itself — from a shadow root, ::slotted() cannot reach the cells, so this is document-level CSS by design.

DateItemAmount
2026-09-18Invoice #10421,240.00
2026-09-19Refund−80.00
2026-09-20Pending–
<div class="glass-table-wrap"> <table class="glass-table"> <thead><tr><th>Date</th><th class="glass-table__num">Amount</th></tr></thead> <tbody><tr><td>2026-09-18</td><td class="glass-table__num">1,240.00</td></tr></tbody> </table> </div>
ClassDescription
.glass-table-wrapOptional horizontal scroll container
.glass-tableThe table: hairline rows, hover highlight
.glass-table__numRight-aligned, tabular figures — on th and td
.glass-table__mutedSecondary text colour on a cell

Prose

Running text the app did not write by hand — rendered Markdown, help and info pages. One class on the container styles headings, paragraphs, lists, links, code, quotes, images and tables. Document-level by design: the content is light DOM, and ::slotted() stops at the first level.

Getting started

Include glasskit.css, set data-theme on <html>, done. Everything else is optional — see the design tokens.

  • Dark mode is the default
  • Light mode via data-theme="light"
The glass effect needs a coloured background to show.
<article class="glass-prose"> <!-- rendered Markdown: h1–h3, p, ul/ol, a, code, pre, blockquote, img, hr, table --> </article>

Segmented

A small, exclusive choice as one control — traffic light, morning / afternoon, mode. Buttons inside a role="group"; the chosen one carries aria-pressed="true", and the styling hangs on exactly that attribute, so state and semantics cannot drift apart. The tone modifiers put a dot in a state colour before the label. Try it: click or Tab to a button and press Space. More options than fit? Without a modifier the row stays one line and runs past the edge; --scroll lets it scroll sideways, --wrap breaks it into lines. Both combine with --full.

<div class="glass-segmented glass-segmented--full" role="group" aria-label="Status"> <button class="glass-segmented__item glass-segmented__item--success" aria-pressed="true"> <span class="glass-segmented__dot"></span>Green </button> <button class="glass-segmented__item" aria-pressed="false">Help page</button> </div>
ClassDescription
.glass-segmentedThe group: inset glass track, buttons inside
--fullButtons share the width
--scrollOne row that scrolls sideways when the options do not fit, scrollbar hidden (since 1.17.0)
--wrapBreaks the row into lines when the options do not fit (since 1.17.0)
__itemOne option; aria-pressed="true" marks the chosen one, disabled dims it
__item--success / --warning / --errorTone: sets --gl-segmented-tone for the dot
__dotThe dot before the label, in the tone colour

Steps

Progress through a short flow: numbered circles joined by hairlines, done ones on the success surface (with an SVG check), the current one in the primary colour and marked aria-current="step".

  1. Day
  2. Slot
  3. 3Dog
  4. 4Confirm

The list is a size container: narrower than 360 px only the current step keeps its label, the others show their number; before that, labels shorten with an ellipsis. Keyed to the block's own width, not the viewport — here in a 300 px frame:

  1. Day
  2. 2Choose a slot
  3. 3Dog
  4. 4Confirm
<ol class="glass-steps"> <li class="glass-steps__item glass-steps__item--done"> <span class="glass-steps__num"><!-- check SVG --></span><span class="glass-steps__label">Day</span> </li> <li class="glass-steps__line" aria-hidden="true"></li> <li class="glass-steps__item glass-steps__item--current" aria-current="step"> <span class="glass-steps__num">2</span><span class="glass-steps__label">Slot</span> </li> </ol>
ClassDescription
.glass-stepsThe list; a size container, so give it a width inside a flex row
__item, __item--done, __item--currentOne step and its states
__numThe circle: number, or an SVG check when done
__labelThe label; hidden below 360 px except on the current step
__lineHairline connector between steps

Sheet

The bottom sheet is the mobile sibling of the modal: an overlay that fades and a panel that rises from the bottom edge, only the top corners rounded, a grip, safe-area padding. Its own block, not a modal modifier, because layout, entry motion and gesture differ. --inline embeds the panel in the flow without an overlay; the overlay form needs a little JavaScript, shown below and mirrored by <glk-sheet> in GlassKit Elements.

Rebook to …

Sheet content: a list, text, a form. This one is inline.
<div class="glass-sheet-overlay" hidden> <div class="glass-sheet" role="dialog" aria-modal="true"> <div class="glass-sheet__grip"></div> <h2 class="glass-sheet__title">Rebook to …</h2> <div class="glass-sheet__body">…</div> <div class="glass-sheet__actions">…</div> </div> </div> // show: remove hidden, force a reflow, add .is-active next frame // hide: remove .is-active, set hidden after transitionend (fallback 400 ms)
ClassDescription
.glass-sheet-overlayFixed overlay: scrim, blur, panel aligned to the bottom; starts at opacity 0
.is-activeOverlay visible, panel risen — toggled by script
.glass-sheetThe panel: milky glass, top corners rounded, bottom safe-area padding
--inlineIn the flow, no overlay, all corners rounded
__grip, __title, __body, __actionsGrip bar, heading, body, action column

Empty state

For empty lists and result pages: a centred column with a round icon plate, a title, a short muted text and room for one action or several, side by side.

No bookings yet

Pick a day and a dog — the team is looking forward to it.

<div class="glass-empty"> <span class="glass-empty__icon"><!-- SVG --></span> <p class="glass-empty__title">No bookings yet</p> <p class="glass-empty__text">…</p> <div class="glass-empty__action">…</div> </div>
ClassDescription
.glass-emptyCentred column
__icon48 px round plate, 24 px stroked icon inside (::slotted(svg) twin for Elements)
__title, __textHeading and muted text (max 38 ch)
__actionRoom for one action or several: side by side with 8 px between them, wrapping and centred when narrow (since 1.17.0)

Date strip

A row of day chips that scrolls sideways — a booking horizon, the days around today. Each chip is a <button> with the weekday, the day number and a dot that a tone modifier lights up; without a tone the dot is transparent, so chips with and without a mark keep the same height. The chosen chip carries aria-pressed="true", as in the segmented control; :disabled or aria-disabled="true" dims a day that cannot be chosen. The scrollbar is hidden. Give each button an aria-label with the full date — the visible “Tu 22” is no name. <glk-date-strip> in GlassKit Elements builds this from dates, with arrow keys and the chosen chip centred.

<div class="glass-date-strip" role="group" aria-label="Pick a day"> <button class="glass-date-strip__day glass-date-strip__day--today" aria-pressed="false" aria-label="Tuesday, 22 September 2026"> <span class="glass-date-strip__wd">Tu</span><span class="glass-date-strip__num">22</span> <span class="glass-date-strip__mark glass-date-strip__mark--success"></span> </button> <button class="glass-date-strip__day" aria-pressed="true" aria-label="…">…</button> <button class="glass-date-strip__day" aria-pressed="false" disabled>…</button> </div>
ClassDescription
.glass-date-stripScrolling row; hidden scrollbar; 4 px padding so its own overflow does not clip the focus ring
__dayChip button, 44 px minimum; [aria-pressed="true"] chosen, :disabled / [aria-disabled="true"] dimmed
__day--todayUnderlines the number
__wd, __numWeekday in small caps, day number
__mark6 px dot; transparent without a tone
__mark--primary, --success, --warning, --errorTone of the dot via --gl-date-strip-tone; on the chosen chip every tone becomes the ink on primary (--gl-date-strip-ink)

Calendar

One month: a title between two round nav buttons, a weekday row and 42 square day buttons with up to three dots beneath the number. The chosen day carries aria-pressed="true", --today draws a warm border, --other dims a day of the neighbouring month, :disabled or aria-disabled="true" dims a day outside the allowed range — the second keeps it focusable for arrow keys. It is a role="group" of buttons named with their full date, not a role="grid". <glk-calendar> in GlassKit Elements builds it, with keyboard navigation and Intl names.

September 2026
<div class="glass-calendar"> <div class="glass-calendar__head"> <button class="glass-calendar__nav" aria-label="Previous month"><!-- SVG chevron --></button> <div class="glass-calendar__title">September 2026</div> <button class="glass-calendar__nav" aria-label="Next month">…</button> </div> <div class="glass-calendar__grid" role="group" aria-label="Pick a day"> <span class="glass-calendar__wd" aria-hidden="true">Mo</span> <!-- × 7 --> <button class="glass-calendar__day glass-calendar__day--other" aria-pressed="false" aria-label="Monday, 31 August 2026"> <span>31</span><span class="glass-calendar__marks"></span> </button> <button class="glass-calendar__day glass-calendar__day--today" aria-pressed="true" aria-label="…"> <span>22</span><span class="glass-calendar__marks"><span class="glass-calendar__mark glass-calendar__mark--warning"></span></span> </button> <!-- 42 cells --> </div> </div>
ClassDescription
.glass-calendarBlock; __head with __title (ellipsis when tight) and two __nav buttons, 32 px round, with an SVG chevron
__gridSeven columns, 4 px gap
__wdWeekday header cell, muted small caps
__daySquare day button; [aria-pressed="true"] chosen, --today warm border, --other dimmed neighbour month, :disabled / [aria-disabled="true"] dimmed and unpickable
__marks, __mark5 px dots beneath the number, up to three; __mark--primary / --success / --warning / --error via --gl-calendar-tone, the ink on the chosen day via --gl-calendar-ink

Image picker

Choosing one image with a preview: a 72 px plate — the picture with object-fit: cover, or a placeholder icon — and a column with the label, a hint and the actions, which are ordinary .glass-btn buttons; the block brings no button look of its own. --round makes the plate a circle for avatars; a long label wraps and never squeezes the plate. Any image, not only photos. <glk-image-picker> in GlassKit Elements adds the file dialog, EXIF rotation and resizing.

Photo of the dog JPG or PNG Β· resized to 1024 px before upload
Profile photo
<div class="glass-image-picker" role="group" aria-labelledby="photo-label"> <div class="glass-image-picker__preview glass-image-picker__preview--round"><img src="…" alt=""></div> <div class="glass-image-picker__meta"> <span class="glass-image-picker__label" id="photo-label">Profile photo</span> <span class="glass-image-picker__hint">JPG or PNG</span> <div class="glass-image-picker__actions"> <button class="glass-btn glass-btn--secondary glass-btn--sm glass-btn--auto">Change</button> <button class="glass-btn glass-btn--tertiary glass-btn--sm glass-btn--auto">Remove</button> </div> </div> </div>
ClassDescription
.glass-image-pickerRow: plate left, column right, 14 px gap
__preview72 px plate; img covers it, svg is the 28 px placeholder in the muted icon colour
__preview--roundCircle, for avatars
__metaColumn that yields (min-width: 0)
__label, __hintLabel in the look of .glass-label, wraps anywhere; small muted hint
__actionsWrapping row of .glass-btn buttons

Utilities

Stack (vertikal)

.gl-stack .gl-stack--xs (8px) .gl-stack--sm (12px) .gl-stack--md (16px) .gl-stack--lg (20px) .gl-stack--xl (24px)

Row (horizontal)

.gl-row .gl-row--xs (8px) .gl-row--sm (12px) .gl-row--md (16px)

Margin Top

.gl-mt-sm (12px) .gl-mt-md (16px) .gl-mt-lg (20px) .gl-mt-xl (24px)

Margin Bottom

.gl-mb-sm (12px) .gl-mb-md (16px) .gl-mb-lg (20px) .gl-mb-xl (24px)

Text

.gl-text-center .gl-text-muted .gl-text-sm

Layout

.gl-px (padding horizontal) .gl-w-full (width: 100%) .gl-flex-1 (flex: 1)

πŸ“‹ All Classes at a Glance

ComponentClassesModifier / States
Background.glass-bg--has-tab-bar
Navigation.glass-nav–
Pill-Button.glass-pill:disabled
Theme-Toggle.glass-theme-toggle–
Title.glass-title–
Card.glass-card--glow
Button.glass-btn--primary, --secondary, --tertiary, --sm, --lg, --auto, :disabled
Badge.glass-badge--primary, --success, --warning, --error, --interactive, --selected
Avatar.glass-avatar--sm, --lg
Divider.glass-divider–
Status.glass-status–
List.glass-list--flush, --bare, __item--interactive, __item--center, __item--danger, __item--accent, __leading--lg, __subtitle--wrap, __value, __section-header
Skeleton.glass-skeleton__line, __line--title
Table.glass-table-wrap, __num, __muted
Prose.glass-prose–
Segmented.glass-segmented--full, --scroll, --wrap, __item, __item--success/--warning/--error, __dot, [aria-pressed]
Steps.glass-steps__item, __item--done, __item--current, __num, __label, __line
Sheet.glass-sheet-overlay + .glass-sheet.is-active, --inline, __grip, __title, __body, __actions
Empty state.glass-empty__icon, __title, __text, __action
Date strip.glass-date-strip__day, __day--today, __wd, __num, __mark, __mark--primary/--success/--warning/--error, [aria-pressed], :disabled
Calendar.glass-calendar__head, __title, __nav, __grid, __wd, __day, __day--today, __day--other, __marks, __mark--primary/--success/--warning/--error, [aria-pressed], [aria-disabled]
Image picker.glass-image-picker__preview, __preview--round, __meta, __label, __hint, __actions
Popover.glass-popover--top, --start, --end, .is-open
Input.glass-input--error, :disabled; .glass-input-wrap with __prefix / __suffix
Textarea.glass-textarea:disabled
Select.glass-select:disabled
Search.glass-search–
Toggle.glass-toggle:checked, :disabled
Checkbox.glass-checkbox:checked, :disabled
Radio.glass-radio:checked, :disabled
Range.glass-range:disabled
Progress.glass-progress--sm, --lg, --success, --error
Modal.glass-modal-overlay.is-active
Toast.glass-toast--success, --error, --warning, .is-visible, __action, __close
Tab-Bar.glass-tab-bar.is-active auf Items
Tab-Bar Floating.glass-tab-bar-dock + .glass-tab-bar--floating__accessory, __accessory--accent/--success/--error, --accessory-left
Accordion.glass-accordion.is-open auf Items

πŸ€– AI / LLM Reference

GlassKit ships with SKILL.md – a structured, machine-readable component reference designed for AI assistants, LLMs, and code-generation tools.

FeatureDescription
Copy-paste HTMLAll 34 components with exact nesting and BEM hierarchy
Design token tablesColors, surfaces, blur, radii, spacing, shadows, typography
State class mappingis-active, is-open, is-visible, :checked – where each belongs
Composition patterns6 full page layouts: Login, Dashboard, Form, Modal, Settings, Progress
Common mistakesFrequent errors and their corrections

Attach or reference SKILL.md when asking an AI to generate GlassKit HTML for production-ready output.

# File location glasskit/SKILL.md # Also included in the npm package npm install @jungherz-de/glasskit node_modules/@jungherz-de/glasskit/SKILL.md

🧩 The GlassKit Family

GlassKit is the CSS foundation of a three-layer family – three layers, one design language. For everything beyond single components, the sister projects are the intended path.

LayerProjectUse it for
CSS foundation🧊 GlassKit (you are here)The design language: pure-CSS components, design tokens, dark & light.
App layerGlassKit ElementsDrop-in web components (glk-button, glk-card, …) for application UIs.
Website layerGlassKit WebBuilding a complete website – the official Astro template with sections, i18n and SEO on the GlassKit foundation.