@jungherz-de/glasskit 1.31.0 → 1.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +141 -1
- package/README.md +161 -22
- package/SKILL.md +575 -22
- package/glasskit-droplet.js +70 -32
- package/glasskit-styles.js +2 -2
- package/glasskit.css +934 -35
- package/glasskit.min.css +1 -1
- package/glasskit.min.css.map +1 -1
- package/package.json +2 -2
- package/theme-override.css +119 -0
package/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: glasskit-css
|
|
3
|
-
description: GlassKit is a pure CSS glassmorphism component library (v1.
|
|
3
|
+
description: GlassKit is a pure CSS glassmorphism component library (v1.33.0) with 38 components, Dark & Light mode, design tokens, and BEM-like naming. Use this reference whenever generating HTML that uses GlassKit classes to ensure correct structure, nesting, modifiers, and token usage.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# GlassKit CSS – AI Component Reference
|
|
@@ -12,6 +12,10 @@ description: GlassKit is a pure CSS glassmorphism component library (v1.31.0) wi
|
|
|
12
12
|
|
|
13
13
|
> **New in 1.28.0 — icons of any kind, and tokens instead of overrides.** Tab bar, accessory and segmented control colour their icon box, not the SVG: put a font icon (Material Icons), an `<img>` mask or a custom element straight into `.glass-tab-bar__icon` or `.glass-segmented__icon`, and it follows every state, the lens of the drop and the drag. `--icons` makes an icon-only segmented row (light / dark / auto). The inactive tab colour, the hover colour, the label size and the z-index of the tab bar are tokens, and so are the surface, shadow and text colour of the chosen segmented option. **Where a project restyles tab icons per state, or overrides the tab bar's literals, replace that with the tokens** (3.4, 3.29).
|
|
14
14
|
|
|
15
|
+
> **New in 1.32.0 — one navigation for every edge, four components, and AA on the accent fills.** The tab bar leaves the bottom edge: `--vertical` makes it a sidebar, `--start` or `--end` fixes it to that side of the viewport — where the thumb rests on a phone held open, or a foldable that moved its system controls to a side — `--rail` shrinks it to icons, `--top` lays it out for the top of a page, and the floating bar stands upright in `.glass-tab-bar-dock--vertical`. In a column the drop runs along y, and its timing is tokens (`--gl-droplet-*`). New: the tooltip, the menu, the tree and the breadcrumbs (3.36–3.39), the states of a drag that reorders a list or a tree (3.40), and for the table a sort button, a sticky header, a row action column, an empty row and a card layout (3.27). Popover, tooltip and menu open in the top layer with the `popover` attribute. `--gl-btn-primary-bg` and `--gl-color-primary-fill` darken the accent fills for white text without touching the brand colour, and the radio's dot follows `--gl-color-on-primary`. **Where a project builds its own sidebar, tooltip, menu, tree or breadcrumbs, overrides the drop's transitions, or darkens `--gl-color-primary` for white button text, replace that** (3.4, 3.7, 3.25, section 2).
|
|
16
|
+
|
|
17
|
+
> **New in 1.33.0 — a rail that names its items, and tokens for the tab bar's details.** `--rail` with `--labels` keeps the label under the icon, and `--floating` with `--vertical` and `--start` or `--end` makes the rail a pane of its own glass at that edge, full height and inset from it; `__leading` and `__trailing` hold a mark, the accessory (`__accessory-item` with its name under it) and a foot inside the bar. `--gl-tab-bar-icon-size`, `--gl-tab-bar-item-radius` and `--gl-tab-bar-active-weight` replace overrides of global tokens, and the items transition only colour, surface, shadow, opacity and the press. Also new: `.glass-input-group--label-end` for a link such as "Forgot password?" at the end of the label row, and `.glass-badge--md`, a 36px choice chip with a 44px tap target.
|
|
18
|
+
|
|
15
19
|
---
|
|
16
20
|
|
|
17
21
|
## 1. Setup & Boilerplate
|
|
@@ -166,7 +170,8 @@ All are derived from the state color via `color-mix()`, so overriding
|
|
|
166
170
|
|
|
167
171
|
| Token | Role | Default |
|
|
168
172
|
|---|---|---|
|
|
169
|
-
| `--gl-color-on-primary` | Ink/icons **on** the primary fill | `#ffffff` |
|
|
173
|
+
| `--gl-color-on-primary` | Ink/icons **on** the primary fill — the button, the checkbox tick, the radio's dot (since 1.32.0), the accent accessory, the chosen day, the current step | `#ffffff` |
|
|
174
|
+
| `--gl-color-primary-fill` | The flat accent fills that carry text: the chosen day of `.glass-date-strip` and `.glass-calendar`, the number of the current step (since 1.32.0) | unset → `var(--gl-color-primary)` |
|
|
170
175
|
| `--gl-color-on-success` | Ink/icons on a filled success surface | `#ffffff` |
|
|
171
176
|
| `--gl-color-on-error` | Ink/icons on a filled error surface | `#ffffff` |
|
|
172
177
|
| `--gl-color-primary-on-surface` | Badge text on the primary tint | lightened (dark) / darkened (light) primary |
|
|
@@ -198,6 +203,31 @@ fully-translucent pre-1.7.0 chip.
|
|
|
198
203
|
>
|
|
199
204
|
> That reaches 4,62:1. Badges are unaffected — they already pass by default.
|
|
200
205
|
|
|
206
|
+
> **AA on the accent fills, keeping white (since 1.32.0).** The primary button's gradient starts at `--gl-color-primary`, and the chosen days and the current step are filled with it — but the same token draws focus rings, borders, the tab bar's spotlight and the accent as text, so darkening it changes them all. Two hooks darken the fills alone, both unset: `--gl-btn-primary-bg`, the whole background of `.glass-btn--primary`, and `--gl-color-primary-fill`, the flat fills that carry text. On GlassKit's orange, white reaches 4.5:1 from `color-mix(in srgb, var(--gl-color-primary) 75%, #000)` in the light theme and from 65 % in the dark one:
|
|
207
|
+
>
|
|
208
|
+
> ```css
|
|
209
|
+
> :root, [data-theme="dark"] { --gl-color-primary-fill: color-mix(in srgb, var(--gl-color-primary) 65%, #000); }
|
|
210
|
+
> [data-theme="light"] { --gl-color-primary-fill: color-mix(in srgb, var(--gl-color-primary) 75%, #000); }
|
|
211
|
+
> :root, [data-theme="dark"], [data-theme="light"] {
|
|
212
|
+
> --gl-btn-primary-bg: linear-gradient(135deg, var(--gl-color-primary-fill), color-mix(in srgb, var(--gl-color-primary-dark) 80%, #000));
|
|
213
|
+
> }
|
|
214
|
+
> ```
|
|
215
|
+
>
|
|
216
|
+
> White then reads 4.53:1 on the fill, and the gradient stays at or above that on every point; the weekday on the chosen day of the date strip is as strong as the number since 1.32.0, so it reaches the same. The other way keeps the fills and switches the ink — the 17 % mix above, 4.60:1 or more on all three stops of the button. Since 1.32.0 the radio's dot follows the ink like the checkbox tick, so a dark ink needs no rule for the radio.
|
|
217
|
+
>
|
|
218
|
+
> Where the brand colour is set at run time, `contrast-color()` picks black or white by itself. Put it behind `@supports`, with the 17 % mix as the fallback; on GlassKit's orange it gives black, 5.56:1 or more (light) and 5.85:1 or more (dark) on the button's stops. It looks at the primary alone — with a fill of your own, or a gradient that ends much darker, measure the other end as well.
|
|
219
|
+
>
|
|
220
|
+
> ```css
|
|
221
|
+
> :root, [data-theme="dark"], [data-theme="light"] {
|
|
222
|
+
> --gl-color-on-primary: color-mix(in srgb, var(--gl-color-primary) 17%, #000);
|
|
223
|
+
> }
|
|
224
|
+
> @supports (color: contrast-color(red)) {
|
|
225
|
+
> :root, [data-theme="dark"], [data-theme="light"] {
|
|
226
|
+
> --gl-color-on-primary: contrast-color(var(--gl-color-primary));
|
|
227
|
+
> }
|
|
228
|
+
> }
|
|
229
|
+
> ```
|
|
230
|
+
|
|
201
231
|
> **AA by default since 1.31.0** for muted text (`--gl-color-text-muted` 65 % dark / 68 % light), card text (68 % light) and icons (light: muted 55 %, default 65 %, strong 80 %) — text 4.5:1, icons with a meaning 3:1, on the page and on glass. Not for `--gl-color-primary-text`: the light orange reads 2.43:1 as text, but a fixed mix would darken every brand alike. Where a light theme keeps the orange, set `[data-theme="light"] { --gl-color-primary-text: var(--gl-color-primary-on-surface); }` (5.8:1). Never lower the muted tokens again for a lighter look; the inactive tab labels (10px, `--gl-icon-muted`) stay below 4.5:1 — `--gl-tab-bar-color` raises them.
|
|
202
232
|
|
|
203
233
|
> **Do not put text in `--gl-color-success` / `--error` / `--primary` on a tinted
|
|
@@ -426,7 +456,7 @@ Theme Toggle (specialized pill):
|
|
|
426
456
|
|
|
427
457
|
### 3.4 Tab Bar
|
|
428
458
|
|
|
429
|
-
Fixed bottom navigation with glass background. Requires `glass-bg--has-tab-bar` on the background container. The items sit in the middle of the bar; with a home indicator (an iPhone with `viewport-fit=cover`) they keep to the top, above it (since 1.28.0).
|
|
459
|
+
Fixed bottom navigation with glass background. Requires `glass-bg--has-tab-bar` on the background container. The items sit in the middle of the bar; with a home indicator (an iPhone with `viewport-fit=cover`) they keep to the top, above it (since 1.28.0). The same bar is also a sidebar, an icon rail or a top bar (since 1.32.0, see "Sidebar, rail, top bar and side dock" below).
|
|
430
460
|
|
|
431
461
|
```html
|
|
432
462
|
<nav class="glass-tab-bar">
|
|
@@ -455,8 +485,8 @@ Fixed bottom navigation with glass background. Requires `glass-bg--has-tab-bar`
|
|
|
455
485
|
| Class | Description |
|
|
456
486
|
|---|---|
|
|
457
487
|
| `.glass-tab-bar` | Container: fixed bottom, glass blur |
|
|
458
|
-
| `.glass-tab-bar__item` | Individual tab |
|
|
459
|
-
| `.glass-tab-bar__item.is-active` | Active tab: icon and label in `--gl-tab-bar-active-color` where set, else `--gl-color-primary-text` (since 1.26.0; both default to the primary); glow and dot in the primary |
|
|
488
|
+
| `.glass-tab-bar__item` | Individual tab — a `<button>`, or an `<a>` that can open its view in a new tab (since 1.32.0); a focus ring for the keyboard on every bar (since 1.32.0) |
|
|
489
|
+
| `.glass-tab-bar__item.is-active` | Active tab: icon and label in `--gl-tab-bar-active-color` where set, else `--gl-color-primary-text` (since 1.26.0; both default to the primary); glow and dot in the primary. Give it `aria-current="page"` too, so a screen reader tells which view is open |
|
|
460
490
|
| `.glass-tab-bar__icon` | Icon wrapper; carries the state colour (since 1.28.0): an SVG strokes in `currentColor`, a font icon or any other element inherits it |
|
|
461
491
|
| `.glass-tab-bar__badge` | Numeric badge inside icon |
|
|
462
492
|
| `.glass-tab-bar__label` | Text label below icon |
|
|
@@ -477,10 +507,14 @@ Every state — inactive, hover, active, under the drop, the drag — sets `colo
|
|
|
477
507
|
| `--gl-tab-bar-color` | `--gl-icon-muted` | Icon and label of the inactive tabs; `var(--gl-icon-strong)` reads better on a busy background |
|
|
478
508
|
| `--gl-tab-bar-hover-color` | `--gl-icon-default` | Icon and label of a hovered tab — set it too when `--gl-tab-bar-color` is lighter than `--gl-icon-default`, or hover dims the tab |
|
|
479
509
|
| `--gl-tab-bar-label-size` | `10px` | Label size (Material uses 12px, Apple's HIG about 13px) |
|
|
510
|
+
| `--gl-tab-bar-icon-size` | `24px` | Size of the icon box and of an SVG in it (since 1.33.0); a compact top bar takes the segmented control's 18px |
|
|
511
|
+
| `--gl-tab-bar-active-weight` | `--gl-font-weight-medium` | Weight of the active tab's label (since 1.33.0), e.g. `var(--gl-font-weight-semibold)` |
|
|
480
512
|
| `--gl-tab-bar-z-index` | `900` | Stacking of `.glass-tab-bar` and `.glass-tab-bar-dock`, e.g. below a side drawer |
|
|
481
513
|
|
|
482
514
|
Never copy the state rules onto an icon element of your own, and never override `stroke` on `.glass-tab-bar__icon svg`: since 1.28.0 such a rule reaches every state, the active one too. Set the tokens.
|
|
483
515
|
|
|
516
|
+
**Transitions (since 1.33.0).** The items move only what a state changes — `color`, `background-color`, `box-shadow`, `opacity`, `transform` — not `all`. A bar that switches its layout (upright, floating, a rail) takes its new size at once; with `all`, padding, width and height glided for 250ms and an item measured meanwhile was not yet its size. Do not put `transition: all` back on the items.
|
|
517
|
+
|
|
484
518
|
#### Floating variant + Accessory
|
|
485
519
|
|
|
486
520
|
Pill-shaped, centered, floating bar (iOS 26 Liquid Glass style). Wrap it in `.glass-tab-bar-dock` together with an optional `.glass-tab-bar__accessory` capsule (e.g. search, compose). Use `.glass-bg--has-tab-bar-floating` on the background container instead of `--has-tab-bar`. The active item gets a soft radial Spotlight halo.
|
|
@@ -528,10 +562,46 @@ Pill-shaped, centered, floating bar (iOS 26 Liquid Glass style). Wrap it in `.gl
|
|
|
528
562
|
|
|
529
563
|
- **The stylesheet draws the drop, the optional module moves it.** `glasskit-droplet.js` (no dependencies, ~4 KB minified) follows `.is-active`, which the page keeps setting its own way, and clicks the tab a drag ends on — the page's own click handler makes the choice. `attachDroplet(row)` attaches one row and returns `{ update(), destroy() }`; attaching twice returns the same handle.
|
|
530
564
|
- **Without the script** the bar keeps its spotlight: everything droplet-specific hangs on `data-droplet`, which only the module sets.
|
|
531
|
-
- **Never write the module's state by hand:** `data-droplet`, `data-droplet-dir`, `data-droplet-lift`, `data-droplet-drag`, `--gl-droplet-left/-right/-top/-bottom` and `.is-under-droplet` belong to it.
|
|
565
|
+
- **Never write the module's state by hand:** `data-droplet`, `data-droplet-dir`, `data-droplet-axis`, `data-droplet-lift`, `data-droplet-drag`, `--gl-droplet-left/-right/-top/-bottom` and `.is-under-droplet` belong to it. The timing tokens below are the project's.
|
|
532
566
|
- The drop takes the active item's surface where it is set (`--gl-tab-bar-active-bg`, `-shadow`, below), else a light glass; its highlight is `--gl-gloss-droplet`. Solid and tint surfaces make it opaque; `prefers-reduced-motion` makes it jump instead of travel. Spotlight, dot and glow are off on a droplet bar.
|
|
533
567
|
- A transform on an ancestor — an app that zooms in on start, a popover opening from `scale(0.96)` — leaves the drop on its item, at rest, while the transform runs and during a drag (since 1.28.0; before, it landed at the scaled position and stayed there).
|
|
534
568
|
- GlassKit Elements: `<glk-tab-bar floating droplet>` does all of it.
|
|
569
|
+
- **Along y (since 1.32.0).** In a column — a `--vertical` tab bar, or a row laid out with `flex-direction: column` or `aria-orientation="vertical"` — the drop runs along y: the module sets `data-droplet-axis="y"` and the directions `down` and `up`, a finger drags it up and down, and the row hands sideways swipes to the page (`touch-action: pan-x`). Along y the drop runs narrower instead of flatter. Nothing to set. In a horizontal bar that is not at the bottom — `--top`, a static bar in a header — it runs as on the bottom edge.
|
|
570
|
+
|
|
571
|
+
**Timing (since 1.32.0).** The motion is tokens, unset today's values, read by the stylesheet and by the module alike, and inherited into GlassKit Elements' `<glk-tab-bar droplet>` and `<glk-segmented droplet>`. Never override the drop's `transition` or `transform` — from outside, one rule hits travel, lift and drag alike.
|
|
572
|
+
|
|
573
|
+
| Token | Unset | Times |
|
|
574
|
+
|---|---|---|
|
|
575
|
+
| `--gl-droplet-duration` | `0.3s` | The leading edge (and the drop's other axis) |
|
|
576
|
+
| `--gl-droplet-easing` | `cubic-bezier(0.3, 1.2, 0.5, 1)` | Its curve |
|
|
577
|
+
| `--gl-droplet-trail-duration` | `0.5s` | The trailing edge |
|
|
578
|
+
| `--gl-droplet-trail-delay` | `40ms` | How long the trailing edge waits |
|
|
579
|
+
| `--gl-droplet-trail-easing` | `cubic-bezier(0.5, 1.5, 0.45, 0.92)` | Its curve |
|
|
580
|
+
| `--gl-droplet-lift` | `0.86` | How flat the drop runs on its way; `1` = not at all |
|
|
581
|
+
| `--gl-droplet-lift-duration` | `280ms` | How long it runs flat before it springs back (read by the module) |
|
|
582
|
+
| `--gl-droplet-settle-duration` | `0.55s` | The spring back |
|
|
583
|
+
| `--gl-droplet-settle-easing` | `cubic-bezier(0.34, 1.8, 0.5, 1)` | Its curve, which overshoots |
|
|
584
|
+
| `--gl-droplet-lens-duration` | `0.4s` | The icon or dot below the drop growing |
|
|
585
|
+
| `--gl-droplet-lens-easing` | `cubic-bezier(0.34, 1.6, 0.5, 1)` | Its curve |
|
|
586
|
+
|
|
587
|
+
The lens follows the drop for the longer of the two edges plus 80ms (620ms unset). A product whose UI motion stays within about 240ms ease-out — the drop then arrives in 240ms, without a tail, in the tab bar and the segmented control alike:
|
|
588
|
+
|
|
589
|
+
```css
|
|
590
|
+
:root {
|
|
591
|
+
--gl-droplet-duration: 240ms;
|
|
592
|
+
--gl-droplet-easing: ease-out;
|
|
593
|
+
--gl-droplet-trail-duration: 240ms;
|
|
594
|
+
--gl-droplet-trail-delay: 0ms;
|
|
595
|
+
--gl-droplet-trail-easing: ease-out;
|
|
596
|
+
--gl-droplet-lift: 1;
|
|
597
|
+
--gl-droplet-lift-duration: 0ms;
|
|
598
|
+
--gl-droplet-settle-duration: 0ms;
|
|
599
|
+
--gl-droplet-lens-duration: 240ms;
|
|
600
|
+
--gl-droplet-lens-easing: ease-out;
|
|
601
|
+
}
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
Keep `--gl-droplet-lift-duration: 0ms` in it: without it the lift's deeper shadow still fades back until about 600ms. With it every edge stops after about 250ms and the shadow settles within 40ms (measured in Chromium, WebKit and Firefox). `prefers-reduced-motion: reduce` still makes the drop jump, whatever the tokens say.
|
|
535
605
|
|
|
536
606
|
#### Active item surface (since 1.27.0)
|
|
537
607
|
|
|
@@ -546,6 +616,110 @@ Tokens for a capsule behind the active item, like the selected tab of iOS 26 —
|
|
|
546
616
|
|
|
547
617
|
A nearly opaque white capsule (`rgba(255, 255, 255, 0.9)`) lets a dark brand primary stay the active colour in the dark theme. The capsule is the item's background, rounded like the item: a pill on the floating bar, 12px on the fixed one.
|
|
548
618
|
|
|
619
|
+
`--gl-tab-bar-item-radius` (since 1.33.0) rounds the floating items and the drop together — unset a capsule (`--gl-radius-full`); in a rail with labels unset 16px. Set it on the bar instead of `--gl-radius-full`, which every pill and badge shares: 18px for the rounded squares of a rail, 12px for a compact top bar that looks like a segmented control.
|
|
620
|
+
|
|
621
|
+
#### Sidebar, rail, top bar and side dock (since 1.32.0)
|
|
622
|
+
|
|
623
|
+
One navigation in more places than the bottom edge. The items stay the same — icon, label, badge, `.is-active`, the drop — and only the bar's modifiers change, so a page switches between the layouts (a media query in script, a setting per device) without rendering the items again.
|
|
624
|
+
|
|
625
|
+
```html
|
|
626
|
+
<!-- Sidebar, placed by the page's layout: a grid column, as high as its container -->
|
|
627
|
+
<div style="display: grid; grid-template-columns: 240px 1fr; height: 100dvh">
|
|
628
|
+
<nav class="glass-tab-bar glass-tab-bar--vertical glass-tab-bar--droplet" aria-label="Main">
|
|
629
|
+
<a class="glass-tab-bar__item is-active" href="/dashboard" aria-current="page">
|
|
630
|
+
<span class="glass-tab-bar__icon"><svg viewBox="0 0 24 24"><!-- Icon --></svg></span>
|
|
631
|
+
<span class="glass-tab-bar__label">Dashboard</span>
|
|
632
|
+
</a>
|
|
633
|
+
<a class="glass-tab-bar__item" href="/customers" aria-label="Customers, 3 new">
|
|
634
|
+
<span class="glass-tab-bar__icon">
|
|
635
|
+
<svg viewBox="0 0 24 24"><!-- Icon --></svg>
|
|
636
|
+
<span class="glass-tab-bar__badge">3</span>
|
|
637
|
+
</span>
|
|
638
|
+
<span class="glass-tab-bar__label">Customers</span>
|
|
639
|
+
</a>
|
|
640
|
+
</nav>
|
|
641
|
+
<main>…</main>
|
|
642
|
+
</div>
|
|
643
|
+
|
|
644
|
+
<!-- Fixed to the end edge of the viewport, clear of its safe area -->
|
|
645
|
+
<nav class="glass-tab-bar glass-tab-bar--vertical glass-tab-bar--end" aria-label="Main">…</nav>
|
|
646
|
+
|
|
647
|
+
<!-- Icon rail: the labels hidden from view, still the items' names -->
|
|
648
|
+
<nav class="glass-tab-bar glass-tab-bar--vertical glass-tab-bar--rail" aria-label="Main">…</nav>
|
|
649
|
+
|
|
650
|
+
<!-- Top bar, in a sticky header -->
|
|
651
|
+
<header style="position: sticky; top: 0; z-index: 10">
|
|
652
|
+
<nav class="glass-tab-bar glass-tab-bar--top" aria-label="Main">…</nav>
|
|
653
|
+
</header>
|
|
654
|
+
|
|
655
|
+
<!-- The floating bar upright at a side, the accessory below it -->
|
|
656
|
+
<div class="glass-tab-bar-dock glass-tab-bar-dock--vertical glass-tab-bar-dock--end">
|
|
657
|
+
<nav class="glass-tab-bar glass-tab-bar--floating glass-tab-bar--vertical glass-tab-bar--droplet" aria-label="Main">…</nav>
|
|
658
|
+
<button class="glass-tab-bar__accessory glass-tab-bar__accessory--accent" aria-label="Compose"><svg viewBox="0 0 24 24"><!-- Icon --></svg></button>
|
|
659
|
+
</div>
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
| Class | Description |
|
|
663
|
+
|---|---|
|
|
664
|
+
| `.glass-tab-bar--vertical` | A column for a sidebar, placed by the page's layout and as high as its container (`height: 100%`): one item per row, the icon before the label at body size, the badge at the row's end — a long label ends `--gl-tab-bar-badge-room` (32px) before it — the active row on `--gl-tab-bar-active-bg` (unset: `--gl-surface-3`) instead of the dot; scrolls when the items do not fit |
|
|
665
|
+
| `.glass-tab-bar--start` / `--end` | With `--vertical`: fixed to that edge of the viewport, full height, clear of the edge's safe area — the side a thumb reaches on a phone held open. Start and end follow the writing direction |
|
|
666
|
+
| `.glass-tab-bar--rail` | With `--vertical`: icons alone, `--gl-tab-bar-rail-width` wide (72px). The label is hidden from view but stays the item's name; the badge goes back to the icon's corner |
|
|
667
|
+
| `.glass-tab-bar--top` | A horizontal bar for the top of a page: in the flow, its border at the bottom, no room for the home indicator; from 640px the icon beside the label, which keeps clear of a badge at the icon's corner |
|
|
668
|
+
| `.glass-tab-bar--floating.glass-tab-bar--vertical` | The floating pill standing upright, its items stacked as on the bottom edge |
|
|
669
|
+
| `.glass-tab-bar-dock--vertical` | The dock at a side, vertically centred: the bar, and below it the accessory (above with `--accessory-left`) |
|
|
670
|
+
| `.glass-tab-bar-dock--start` / `--end` | With `--vertical`: the edge it docks at; unset it is the end |
|
|
671
|
+
|
|
672
|
+
- **Room for a fixed side bar is the page's.** `.glass-bg--has-tab-bar` and `--has-tab-bar-floating` pad the bottom edge only; next to a bar fixed with `--start` or `--end`, pad the content on that side (`padding-inline-start` or `-end` as wide as the bar). A sidebar in a grid column needs nothing.
|
|
673
|
+
- **A rail shows its labels as tooltips.** The hidden label already names the item, so the tooltip beside the rail is for the eye only: a `.glass-tooltip` (3.36) with `aria-hidden="true"`, on hover, keyboard focus and a long press. GlassKit Elements' rail does this.
|
|
674
|
+
- **Name and state.** Name every navigation with `aria-label` when a page has more than one, mark the open view with `aria-current="page"`, and word a count in the item's name — `aria-label="Customers, 3 new"` instead of "3 Customers".
|
|
675
|
+
- **Every bar, the bottom one too,** shows a focus ring on the item that has the keyboard focus — the active item under the drop included — and an item may be an `<a>` (no underline, the bar's colours).
|
|
676
|
+
- The drop runs along y in a column (see Droplet above); `--vertical` with `--droplet` needs nothing else.
|
|
677
|
+
|
|
678
|
+
#### Rail with labels, floating rail, leading and trailing places (since 1.33.0)
|
|
679
|
+
|
|
680
|
+
A desktop rail that names its items: `--labels` next to `--rail` keeps the label under the icon. With `--floating` the rail is a pane of its own glass, as high as its container with the corners of a card; with `--start` or `--end` as well, it stands at that edge of the viewport, full height less `--gl-tab-bar-floating-inset` at both ends and that far from its edge, clear of the safe areas, with the corners of a card. `__leading` and `__trailing` are places inside the bar: above the items in a column (a mark, the accessory) and at its far end (a foot such as the account); before and after the items in a row.
|
|
681
|
+
|
|
682
|
+
```html
|
|
683
|
+
<nav class="glass-tab-bar glass-tab-bar--floating glass-tab-bar--vertical glass-tab-bar--start
|
|
684
|
+
glass-tab-bar--rail glass-tab-bar--labels glass-tab-bar--droplet"
|
|
685
|
+
aria-label="Main" style="--gl-tab-bar-rail-width: 96px; --gl-tab-bar-label-size: 12px">
|
|
686
|
+
<div class="glass-tab-bar__leading">
|
|
687
|
+
<img src="mark.svg" alt="" width="40" height="40">
|
|
688
|
+
<div class="glass-tab-bar__accessory-item">
|
|
689
|
+
<button class="glass-tab-bar__accessory glass-tab-bar__accessory--accent" aria-label="Assistant"><svg viewBox="0 0 24 24"><!-- Icon --></svg></button>
|
|
690
|
+
<span class="glass-tab-bar__accessory-label" aria-hidden="true">Assistant</span>
|
|
691
|
+
</div>
|
|
692
|
+
</div>
|
|
693
|
+
<a class="glass-tab-bar__item is-active" href="/" aria-current="page">
|
|
694
|
+
<span class="glass-tab-bar__icon"><svg viewBox="0 0 24 24"><!-- Icon --></svg></span>
|
|
695
|
+
<span class="glass-tab-bar__label">App</span>
|
|
696
|
+
</a>
|
|
697
|
+
<!-- more items -->
|
|
698
|
+
<div class="glass-tab-bar__trailing"><!-- the account --></div>
|
|
699
|
+
</nav>
|
|
700
|
+
<main style="padding-inline-start: calc(96px + 2 * 16px)">…</main>
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
| Class | Description |
|
|
704
|
+
|---|---|
|
|
705
|
+
| `.glass-tab-bar--labels` | With `--rail`: the label under the icon at `--gl-tab-bar-label-size`; the items fill the rail's width (`--gl-tab-bar-rail-width`) and are at least `--gl-tab-bar-rail-item-height` (62px) high, rounded by `--gl-tab-bar-item-radius` (unset 16px), and so is the drop; a long label ends in an ellipsis; no tooltips needed |
|
|
706
|
+
| `--floating` + `--vertical` + `--rail` | A rail of its own glass, docked or not: as high as its container, corners `--gl-tab-bar-rail-radius` (unset `--gl-radius-card`), padding `--gl-space-sm` / `--gl-space-xs`. With `--start` / `--end` as well, fixed at that edge: `top` / `bottom` and the side `--gl-tab-bar-floating-inset` (16px) plus the safe area; mirrored right to left |
|
|
707
|
+
| `.glass-tab-bar__leading` / `__trailing` | Places inside the bar before and after the items: in a column above them and at the far end (`margin-block-start: auto`), in a row before and after them; hide an empty one with `hidden` |
|
|
708
|
+
| `.glass-tab-bar__accessory-item` | The accessory over its name, `.glass-tab-bar__accessory-label` — the name is the button's `aria-label` too, so the visible one is `aria-hidden`; let a click on it press the button |
|
|
709
|
+
|
|
710
|
+
| Token | Unset | Effect |
|
|
711
|
+
|---|---|---|
|
|
712
|
+
| `--gl-tab-bar-rail-width` | `72px` | Width of the rail (a labelled one usually 96px) |
|
|
713
|
+
| `--gl-tab-bar-rail-item-height` | `62px` | Least height of an item in a rail with labels |
|
|
714
|
+
| `--gl-tab-bar-item-radius` | a capsule; `16px` in a rail with labels | Corners of the floating items, the labelled rail's items and the drop |
|
|
715
|
+
| `--gl-tab-bar-floating-inset` | `16px` | Distance of a floating rail at an edge from that edge and from the viewport's ends |
|
|
716
|
+
| `--gl-tab-bar-rail-radius` | `--gl-radius-card` | Corners of a floating rail, docked or not |
|
|
717
|
+
|
|
718
|
+
- **The page keeps the rail's side free**, its width plus the inset on both sides: `padding-inline-start: calc(var(--rail-width) + 2 * 16px)`.
|
|
719
|
+
- **In the flow** (no `--start` / `--end`) a floating rail is the same pane: as high as its container (a grid column), with `--gl-tab-bar-rail-radius` corners and room around its items. Only the compact upright pill without `--rail` — the one in `.glass-tab-bar-dock--vertical` — stays a capsule.
|
|
720
|
+
- **A compact top bar** looks like a segmented control with `--gl-tab-bar-icon-size: 18px`, `--gl-tab-bar-item-radius: 12px` and `--gl-tab-bar-active-weight: var(--gl-font-weight-semibold)` on `.glass-tab-bar--top`.
|
|
721
|
+
- GlassKit Elements: `<glk-tab-bar floating orientation="vertical" dock="start" rail="labels">`, the mark and `<glk-tab-accessory show-label>` in `slot="leading"`, the foot in `slot="trailing"`.
|
|
722
|
+
|
|
549
723
|
---
|
|
550
724
|
|
|
551
725
|
### 3.5 Title
|
|
@@ -634,6 +808,8 @@ Full-width buttons (56px height) with three variants and size modifiers.
|
|
|
634
808
|
|
|
635
809
|
**Shape and room (since 1.31.0)** are button hooks: `--gl-btn-radius` (unset `--gl-radius-btn`, which lists, the status card, toasts, the accordion and the segmented control share — so `--gl-btn-radius: 9999px` gives pill buttons and nothing else changes; never set `--gl-radius-btn` for that) and `--gl-btn-padding-x`, the room beside the label (unset 24px; before, only `--auto` had it and every other button the browser's 6px, so a small button sized by its text touched it). `--sm` reads `--gl-btn-radius-sm` and `--gl-btn-padding-x-sm` first, then those, and keeps its 12px radius while none is set.
|
|
636
810
|
|
|
811
|
+
**Primary background (since 1.32.0):** `--gl-btn-primary-bg` replaces the whole background of `--primary` (unset: the gradient from `--gl-color-primary` over `-mid` to `-dark`), as `--gl-toggle-track-bg-checked` and `--gl-radio-bg-checked` do for toggle and radio. It is how a product keeps white text with AA: start the gradient darker (recipe in section 2, Role Colors). Never darken `--gl-color-primary` for that — it also draws focus rings, borders and the accent as text. The label and icons stay in `--gl-color-on-primary`.
|
|
812
|
+
|
|
637
813
|
**Icons:** Button SVGs need **no inline `fill`/`stroke` attributes** – GlassKit styles them automatically: outline style (`fill: none; stroke: currentColor; stroke-width: 2`, round caps/joins) as the default, `--secondary`/`--tertiary` use their icon tokens, `--primary` renders icons filled. For deliberately filled icons (e.g. brand logos like the GitHub mark) add `glass-icon--fill` to the `<svg>`.
|
|
638
814
|
|
|
639
815
|
**Links as buttons:** `.glass-btn` also works on `<a>` elements – anchors render as `inline-flex` with `text-decoration: none`, so `--auto` shrink-wraps exactly like on a real `<button>`.
|
|
@@ -661,6 +837,7 @@ Tags and labels.
|
|
|
661
837
|
| `.glass-badge--error` | Red |
|
|
662
838
|
| `.glass-badge--interactive` | Pressable chip — cursor, hover tint, focus ring, press feedback |
|
|
663
839
|
| `.glass-badge--selected` | The chip that is on |
|
|
840
|
+
| `.glass-badge--md` | A chip to choose with (since 1.33.0): `--gl-badge-md-height` (36px) high, in the small text of a form; with `--interactive` a tap target of 44px |
|
|
664
841
|
|
|
665
842
|
**Chips (since 1.12.0).** A badge doubles as a filter chip. Use a real `<button>` and carry the state in `aria-pressed`, so the row is operable by keyboard and announced as a toggle — the classes only paint it.
|
|
666
843
|
|
|
@@ -671,6 +848,13 @@ Tags and labels.
|
|
|
671
848
|
aria-pressed="false">Applied</button>
|
|
672
849
|
```
|
|
673
850
|
|
|
851
|
+
**Choice chips (since 1.33.0).** `--md` sizes a chip for a choice in a form — a row of sectors in a sign-up — 36px high (`--gl-badge-md-height`) in `--gl-font-size-sm`. Interactive, it takes taps 4px above and below its edges, 44px in all, the target every other control keeps; leave at least 8px between the lines of a wrapping row so the targets meet without overlapping. Never bend `--gl-space-2xs` or `--gl-font-size-xs` to make chips taller.
|
|
852
|
+
|
|
853
|
+
```html
|
|
854
|
+
<button class="glass-badge glass-badge--md glass-badge--interactive glass-badge--selected" aria-pressed="true">Café & bakery</button>
|
|
855
|
+
<button class="glass-badge glass-badge--md glass-badge--interactive" aria-pressed="false">Restaurant</button>
|
|
856
|
+
```
|
|
857
|
+
|
|
674
858
|
`--selected` deepens the color the badge already carries rather than overruling it, so `glass-badge--success glass-badge--selected` stays green. Each variant points `--gl-badge-accent` at its own color; set that variable on a single badge to give one chip a color of its own. Both states paint through a full-bleed inset shadow instead of `background`, so they layer over a variant's gradient without wiping it.
|
|
675
859
|
|
|
676
860
|
Since 1.7.0 each variant is built from tokens rather than fixed `rgba()` literals —
|
|
@@ -905,6 +1089,8 @@ Date and time fields (`type="date"`, `time`, `datetime-local`, `month`) take the
|
|
|
905
1089
|
| `.glass-input-wrap` | Box around the input that holds a prefix and/or suffix (since 1.22.0) |
|
|
906
1090
|
| `.glass-input-wrap__prefix` / `__suffix` | Icon, currency, unit or button at the field's start / end (logical: they swap sides under `dir="rtl"`) |
|
|
907
1091
|
| `.glass-input-wrap--prefix` / `--suffix` | Makes room in the field; also automatic where `:has()` is supported |
|
|
1092
|
+
| `.glass-input-group--label-end` | The group draws `__label-end` on the label's line, at its end (since 1.33.0) |
|
|
1093
|
+
| `.glass-input-group__label-end` | A link such as "Forgot password?", written **after** the field so the keyboard reaches it after the field |
|
|
908
1094
|
|
|
909
1095
|
**Prefix and suffix (since 1.22.0).** The affixes lie on the field, centred; its padding grows by `--gl-input-prefix-size` / `--gl-input-suffix-size` (18px — an icon — unless set; set it for a wider unit). 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 — before, a disabled button took the click and a `<glk-button>` got none). 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` / `suffix` slots on this and measures the width itself.
|
|
910
1096
|
|
|
@@ -920,6 +1106,16 @@ Date and time fields (`type="date"`, `time`, `datetime-local`, `month`) take the
|
|
|
920
1106
|
|
|
921
1107
|
**Long values, empty labels, picker icon (since 1.25.0).** A value or placeholder too long for the field ends in an ellipsis while the field is not being edited, and a `.glass-label` without text takes no room (`:empty`; it used to keep the group's 8px gap). Date and time fields keep the browser's own picker button; `--gl-input-picker-icon: none` hides it in Chromium (WebKit and Firefox draw none to hide) — for a field whose prefix is the picker; call `showPicker()` from it then. It also hides the arrow of a field with a `<datalist>`.
|
|
922
1108
|
|
|
1109
|
+
**At the end of the label row (since 1.33.0).** A link on the line of the label, such as "Forgot password?" beside "Password": write `.glass-input-group__label-end` after the field and add `--label-end` to the group. The group becomes a grid that draws the link at the end of the label's line, in the label's small text; in the tab order it stays after the field — e-mail, password, "Forgot password?", sign in, the order that reads best in a sign-in form. It works the same around a `.glass-textarea` or `.glass-select`. Never position the link absolutely over the label row. In GlassKit Elements: `slot="label-end"` on `<glk-input>`, `<glk-textarea>` and `<glk-select>`.
|
|
1110
|
+
|
|
1111
|
+
```html
|
|
1112
|
+
<div class="glass-input-group glass-input-group--label-end">
|
|
1113
|
+
<label class="glass-label" for="password">Password</label>
|
|
1114
|
+
<input class="glass-input" id="password" type="password">
|
|
1115
|
+
<a class="glass-input-group__label-end" href="/reset">Forgot password?</a>
|
|
1116
|
+
</div>
|
|
1117
|
+
```
|
|
1118
|
+
|
|
923
1119
|
---
|
|
924
1120
|
|
|
925
1121
|
### 3.15 Textarea
|
|
@@ -1071,7 +1267,7 @@ Animated radio button with dot.
|
|
|
1071
1267
|
|
|
1072
1268
|
**Important:** Radio buttons in the same group need the same `name` attribute value.
|
|
1073
1269
|
|
|
1074
|
-
**Radio tokens (since 1.25.0).** `--gl-radio-bg` / `--gl-radio-bg-checked` (unset `--gl-surface-2` / the primary gradient), `--gl-radio-border` / `--gl-radio-border-checked` (whole border values; unset `1.5px solid` in `--gl-border-medium` / `--gl-border-warm` — give both the same width), `--gl-radio-dot-size` (`10px`; `50%` follows the circle) and `--gl-radio-dot-color` (`white`). A ring that turns the accent colour: `--gl-radio-bg: transparent; --gl-radio-bg-checked: transparent; --gl-radio-border: 2px solid color-mix(in srgb, var(--gl-color-text) 60%, transparent); --gl-radio-border-checked: 2px solid var(--gl-color-primary); --gl-radio-dot-size: 50%; --gl-radio-dot-color: var(--gl-color-primary)`.
|
|
1270
|
+
**Radio tokens (since 1.25.0).** `--gl-radio-bg` / `--gl-radio-bg-checked` (unset `--gl-surface-2` / the primary gradient), `--gl-radio-border` / `--gl-radio-border-checked` (whole border values; unset `1.5px solid` in `--gl-border-medium` / `--gl-border-warm` — give both the same width), `--gl-radio-dot-size` (`10px`; `50%` follows the circle) and `--gl-radio-dot-color` (unset: `--gl-color-on-primary`, white by default — since 1.32.0, so the dot turns dark with the checkbox tick where a project switches the ink; before, `white`). A ring that turns the accent colour: `--gl-radio-bg: transparent; --gl-radio-bg-checked: transparent; --gl-radio-border: 2px solid color-mix(in srgb, var(--gl-color-text) 60%, transparent); --gl-radio-border-checked: 2px solid var(--gl-color-primary); --gl-radio-dot-size: 50%; --gl-radio-dot-color: var(--gl-color-primary)`.
|
|
1075
1271
|
|
|
1076
1272
|
---
|
|
1077
1273
|
|
|
@@ -1263,7 +1459,7 @@ iOS-style grouped settings list. Items can carry a leading icon, a title with op
|
|
|
1263
1459
|
| `.glass-list--bare` | Strips background, border & shadow — for embedding inside `.glass-popover` or `.glass-card`. |
|
|
1264
1460
|
| `.glass-list__section-header` | Section label above a `.glass-list` — uppercase, small, muted |
|
|
1265
1461
|
| `.glass-list__item` | List row (use `<li>`, `<a>`, or `<button>`) |
|
|
1266
|
-
| `.glass-list__item--interactive` | Adds hover / focus / active states |
|
|
1462
|
+
| `.glass-list__item--interactive` | Adds hover / focus / active states; for the keyboard a ring inside the row (since 1.32.0 — the tint alone was too faint) |
|
|
1267
1463
|
| `.glass-list__item--center` | Centered single-text variant with ellipsis truncation |
|
|
1268
1464
|
| `.glass-list__item--danger` | Red text for destructive actions |
|
|
1269
1465
|
| `.glass-list__item--accent` | Primary-colored text for accent actions |
|
|
@@ -1275,6 +1471,7 @@ iOS-style grouped settings list. Items can carry a leading icon, a title with op
|
|
|
1275
1471
|
| `.glass-list__subtitle--wrap` | Multi-line subtitle (up to 3 lines, clamped with ellipsis; `--gl-list-subtitle-lines` sets the limit) |
|
|
1276
1472
|
| `.glass-list__trailing` | Trailing slot — chevron, value, button, badge |
|
|
1277
1473
|
| `.glass-list__value` | Muted text inside `.glass-list__trailing` (e.g. file size) |
|
|
1474
|
+
| `.glass-list__item.is-flash` | A 1.2s flash for an item that changed elsewhere — on another device, by an undo — so the eye finds it; tinted by `--gl-flash-color` (unset: the primary at 30 %), none under `prefers-reduced-motion` (since 1.32.0). Take the class off on `animationend`; GlassKit Elements' `highlight()` sets it |
|
|
1278
1475
|
|
|
1279
1476
|
**Notes:**
|
|
1280
1477
|
- Dividers are auto-rendered via `::after`. The last item never has a divider.
|
|
@@ -1284,6 +1481,7 @@ iOS-style grouped settings list. Items can carry a leading icon, a title with op
|
|
|
1284
1481
|
- Use `<ul>` + `<li>` for semantic lists. For interactive rows wrap in `<a>` or `<button>` instead of `<li>` if a single-row list is needed.
|
|
1285
1482
|
- `.glass-list__section-header` sits **outside** the `.glass-list` container, directly above it.
|
|
1286
1483
|
- `--danger` and `--accent` affect the title and leading icon color; the subtitle stays muted.
|
|
1484
|
+
- **Reordering (since 1.32.0).** The states of a drag that reorders the rows — the faded source, the line where it lands, a row that takes it inside, a grip — are in 3.40; GlassKit Elements' `<glk-list sortable>` drives them by mouse, touch and keyboard.
|
|
1287
1485
|
- **Wrapping text (since 1.23.0).** Title and subtitle keep to one line by default, and `--wrap` clamps the subtitle at three lines. Three inherited tokens change that once for a whole app (`:root`), one list or one row, `<glk-list-item>` included: `--gl-list-title-white-space` and `--gl-list-subtitle-white-space` (`nowrap` by default, `normal` wraps) and `--gl-list-subtitle-lines` (the clamp of `--wrap`, `3` unless set, `none` = every line). A word wider than the column (an e-mail address, a URL) breaks where it has to instead of running out of the row; before 1.23.0 it was clipped in a `--wrap` subtitle. For breaks at syllables set `hyphens: auto; -webkit-hyphens: auto` (optionally `hyphenate-limit-chars: 10 4 4`, so short words stay whole) on `.glass-list` / `glk-list` or the page; it is inherited and follows the page's `lang`.
|
|
1288
1486
|
|
|
1289
1487
|
```css
|
|
@@ -1356,9 +1554,41 @@ Anchored dropdown / menu container. Wrap a trigger button and a `.glass-popover`
|
|
|
1356
1554
|
| `.glass-popover--top` | Opens upward (above the trigger) |
|
|
1357
1555
|
| `.glass-popover--start` | Aligns left edge with trigger |
|
|
1358
1556
|
| `.glass-popover--end` | Aligns right edge with trigger |
|
|
1557
|
+
| `.glass-popover[popover]` | In the top layer (since 1.32.0): shown with `showPopover()` or a `popovertarget` button, `position: fixed` where a script puts it; fades and scales in and out |
|
|
1558
|
+
| `.glass-popover[popover][data-side="top"]` | Written by the placing script when the panel opens above its control: it scales in from its bottom edge |
|
|
1359
1559
|
|
|
1360
1560
|
**Note:** name your toggle function anything except `togglePopover` — that name collides with the native `HTMLElement.togglePopover()` method (HTML Popover API) and inline `onclick` handlers will throw `NotSupportedError`. Use a prefix like `gkTogglePopover` or `myToggle`.
|
|
1361
1561
|
|
|
1562
|
+
**In the top layer (since 1.32.0) — prefer it inside anything that clips.** The anchored panel above hangs absolutely below its trigger: an `overflow: hidden` around it cuts it off, at the screen's edges it runs off, and closed it still widens the page by its box. With the `popover` attribute the same panel opens in the top layer, above every stacking context and outside every box that clips, and takes no room while closed. The browser does not place it next to its control; a script writes its `left` and `top`. With `popover` (auto) and a `popovertarget` button the browser also toggles it, and closes it on a click outside and on Escape:
|
|
1563
|
+
|
|
1564
|
+
```html
|
|
1565
|
+
<button class="glass-btn glass-btn--secondary glass-btn--auto" popovertarget="share-panel">Share</button>
|
|
1566
|
+
<div class="glass-popover" id="share-panel" popover>
|
|
1567
|
+
<ul class="glass-list glass-list--bare">…</ul>
|
|
1568
|
+
</div>
|
|
1569
|
+
|
|
1570
|
+
<script>
|
|
1571
|
+
// Puts a [popover] panel next to its control: below (or above) it, flipped where
|
|
1572
|
+
// the viewport leaves no room, kept 8px inside its edges. Also for .glass-tooltip
|
|
1573
|
+
// and .glass-menu. GlassKit Elements places its panels itself.
|
|
1574
|
+
function gkPlace(panel, anchor, side = 'bottom', gap = 8) {
|
|
1575
|
+
const a = anchor.getBoundingClientRect(), w = panel.offsetWidth, h = panel.offsetHeight;
|
|
1576
|
+
const vw = document.documentElement.clientWidth, vh = document.documentElement.clientHeight;
|
|
1577
|
+
const fits = s => s === 'top' ? a.top - gap - h >= 8 : a.bottom + gap + h <= vh - 8;
|
|
1578
|
+
if (!fits(side)) side = side === 'top' ? 'bottom' : 'top';
|
|
1579
|
+
panel.style.left = `${Math.max(8, Math.min(a.left + a.width / 2 - w / 2, vw - 8 - w))}px`;
|
|
1580
|
+
panel.style.top = `${side === 'top' ? a.top - gap - h : a.bottom + gap}px`;
|
|
1581
|
+
panel.dataset.side = side;
|
|
1582
|
+
}
|
|
1583
|
+
for (const button of document.querySelectorAll('[popovertarget]')) {
|
|
1584
|
+
const panel = document.getElementById(button.getAttribute('popovertarget'));
|
|
1585
|
+
panel.addEventListener('toggle', e => { if (e.newState === 'open') gkPlace(panel, button); });
|
|
1586
|
+
}
|
|
1587
|
+
</script>
|
|
1588
|
+
```
|
|
1589
|
+
|
|
1590
|
+
The panel is fixed to the viewport: place it again on scroll and resize while it is open, or close it. `<glk-popover>` in GlassKit Elements (1.32.0) opens in the top layer and does all of this — flipped and shifted at the viewport's edges, kept at its trigger while the page scrolls.
|
|
1591
|
+
|
|
1362
1592
|
---
|
|
1363
1593
|
|
|
1364
1594
|
### 3.26 Skeleton
|
|
@@ -1403,8 +1633,49 @@ A plain `<table>` on glass (since 1.14.0): hairline rows, a muted header, number
|
|
|
1403
1633
|
| `.glass-table` | The table: hairline rows, hover highlight on body rows |
|
|
1404
1634
|
| `.glass-table__num` | Right-aligned, tabular figures — on `th` and `td` |
|
|
1405
1635
|
| `.glass-table__muted` | Secondary text colour on a cell |
|
|
1636
|
+
| `.glass-table__sort` | A button filling a header cell that sorts by its column (since 1.32.0); the `th` carries `aria-sort` — `ascending`, `descending` or `none` |
|
|
1637
|
+
| `.glass-table__sort-icon` | The arrow in it: faint while the column is unsorted, full on `[aria-sort="ascending"]`, turned on `"descending"` |
|
|
1638
|
+
| `.glass-table-wrap--sticky` + `.glass-table--sticky` | The wrap scrolls both ways, at most `--gl-table-max-height` (60vh) high, and the header cells stick to its top on `--gl-table-header-bg` (since 1.32.0) |
|
|
1639
|
+
| `.glass-table__actions` | A cell for row actions — a menu, icon buttons — end-aligned, as narrow as its content, kept at the row's end while the table scrolls sideways (since 1.32.0) |
|
|
1640
|
+
| `.glass-table--scrolls` | Set by script while the wrap scrolls sideways: the actions cells get a surface and a shadow of their own |
|
|
1641
|
+
| `.glass-table-frame` | Around the wrap: shades its edges where more columns wait — `data-more-start` / `data-more-end` on the frame, set by script (since 1.32.0) |
|
|
1642
|
+
| `.glass-table__empty` | Room below the table for an empty state (a `.glass-empty`) while the body has no rows; `hidden` otherwise (since 1.32.0) |
|
|
1643
|
+
| `.glass-table--list` | Each row a card, the column's name before each value from the cell's `data-label`, the actions at the card's top end — for narrow places (since 1.32.0) |
|
|
1644
|
+
|
|
1645
|
+
**Sorting, a sticky header, row actions, an empty row and cards (since 1.32.0).** What a list of invoices or users needs around the table. GlassKit Elements' `<glk-table>` sets all of it on a native table; in plain markup the script is the page's.
|
|
1646
|
+
|
|
1647
|
+
```html
|
|
1648
|
+
<div class="glass-table-frame">
|
|
1649
|
+
<div class="glass-table-wrap glass-table-wrap--sticky">
|
|
1650
|
+
<table class="glass-table glass-table--sticky">
|
|
1651
|
+
<thead>
|
|
1652
|
+
<tr>
|
|
1653
|
+
<th aria-sort="descending"><button class="glass-table__sort" type="button">Date<svg class="glass-table__sort-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 19V5M6 11l6-6 6 6"/></svg></button></th>
|
|
1654
|
+
<th aria-sort="none"><button class="glass-table__sort" type="button">Customer<svg class="glass-table__sort-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 19V5M6 11l6-6 6 6"/></svg></button></th>
|
|
1655
|
+
<th class="glass-table__num">Amount</th>
|
|
1656
|
+
<th class="glass-table__actions" aria-label="Actions"></th>
|
|
1657
|
+
</tr>
|
|
1658
|
+
</thead>
|
|
1659
|
+
<tbody>
|
|
1660
|
+
<tr>
|
|
1661
|
+
<td data-label="Date">2026-10-27</td>
|
|
1662
|
+
<td data-label="Customer">Jungherz GmbH</td>
|
|
1663
|
+
<td class="glass-table__num" data-label="Amount">1,240.00</td>
|
|
1664
|
+
<td class="glass-table__actions"><button class="glass-btn glass-btn--tertiary glass-btn--sm glass-btn--auto" aria-label="Actions for invoice 1042" aria-haspopup="menu">…</button></td>
|
|
1665
|
+
</tr>
|
|
1666
|
+
</tbody>
|
|
1667
|
+
</table>
|
|
1668
|
+
<div class="glass-table__empty" hidden><!-- a .glass-empty, shown while no row matches --></div>
|
|
1669
|
+
</div>
|
|
1670
|
+
</div>
|
|
1671
|
+
```
|
|
1672
|
+
|
|
1673
|
+
- **Sorting shows a state, it does not sort.** A click on `__sort` flips the `th`'s `aria-sort` and the page sorts the rows (often on the server); every other sortable `th` gets `aria-sort="none"`.
|
|
1674
|
+
- **The sticky header sticks to the wrap, not the page.** With `--sticky` the wrap is the scroller in both directions; set `--gl-table-max-height` to what the page leaves, e.g. `calc(100dvh - 160px)` below a header bar. The header cells draw their bottom line as an inset shadow, so it stays with them while the rows scroll below. Never put `position: sticky` on `th` inside a plain `.glass-table-wrap`: its `overflow-x: auto` makes it a scroll container in both directions, and the header sticks to a box that never scrolls vertically.
|
|
1675
|
+
- **Cards** (`--list`): toggle it below a width — measured on the table's container, not the viewport — and drop `--sticky` meanwhile. Each cell needs `data-label` (empty for the actions); the labels are generated content without a text of their own, so a screen reader does not hear the column twice. The header stays for assistive technology, hidden from view; since the cards change the table's `display`, give the parts explicit roles (`table`, `rowgroup`, `row`, `columnheader`, `cell`), or some browsers drop the table semantics.
|
|
1676
|
+
- **Tokens:** `--gl-table-cell-padding` (`9px 10px`), `--gl-table-header-padding` (`8px 10px`), `--gl-table-max-height` (`60vh`) and `--gl-table-header-bg`, the surface of the sticky header and of the actions while the table scrolls (unset: the theme's middle background at 94 %).
|
|
1406
1677
|
|
|
1407
|
-
> **
|
|
1678
|
+
> **The table stays in the document.** From a shadow root, `::slotted()` matches only the slotted `<table>` itself, never its cells — so a wrapper element cannot style the rows. GlassKit Elements' `<glk-table>` (1.32.0) therefore keeps the native table in the page and only adds around it; the rows take their look from the page's `glasskit.css`. Put the classes on the table in the light DOM.
|
|
1408
1679
|
|
|
1409
1680
|
---
|
|
1410
1681
|
|
|
@@ -1516,7 +1787,7 @@ Progress through a short flow (since 1.15.0): numbered circles joined by hairlin
|
|
|
1516
1787
|
|---|---|
|
|
1517
1788
|
| `.glass-steps` | The list, a size container |
|
|
1518
1789
|
| `.glass-steps__item`, `--done`, `--current` | One step and its states |
|
|
1519
|
-
| `.glass-steps__num` | The circle: number, or an SVG check when done |
|
|
1790
|
+
| `.glass-steps__num` | The circle: number, or an SVG check when done; the current one on `--gl-color-primary-fill` where set (since 1.32.0), else the primary, in `--gl-color-on-primary` |
|
|
1520
1791
|
| `.glass-steps__label` | Label; hidden below 360 px except on the current step |
|
|
1521
1792
|
| `.glass-steps__line` | Hairline connector |
|
|
1522
1793
|
|
|
@@ -1589,9 +1860,9 @@ A row of day chips that scrolls sideways (since 1.16.0) — a booking horizon, t
|
|
|
1589
1860
|
| Class | Description |
|
|
1590
1861
|
|---|---|
|
|
1591
1862
|
| `.glass-date-strip` | Scrolling row, hidden scrollbar, 4 px padding |
|
|
1592
|
-
| `.glass-date-strip__day` | Chip button, 44 px minimum; `[aria-pressed="true"]` chosen on the primary
|
|
1863
|
+
| `.glass-date-strip__day` | Chip button, 44 px minimum; `[aria-pressed="true"]` chosen on `--gl-color-primary-fill` where set (since 1.32.0), else the primary; `:disabled` / `[aria-disabled="true"]` dimmed |
|
|
1593
1864
|
| `.glass-date-strip__day--today` | Underlines the number |
|
|
1594
|
-
| `.glass-date-strip__wd`, `__num` | Weekday in small caps, day number |
|
|
1865
|
+
| `.glass-date-strip__wd`, `__num` | Weekday in small caps, day number; on the chosen chip the weekday is as strong as the number (since 1.32.0; before, faded to 0.75) |
|
|
1595
1866
|
| `.glass-date-strip__mark` | 6 px dot, transparent without a tone |
|
|
1596
1867
|
| `.glass-date-strip__mark--primary`, `--success`, `--warning`, `--error` | Tone via `--gl-date-strip-tone`; on the chosen chip every tone becomes the ink on primary (`--gl-date-strip-ink`) |
|
|
1597
1868
|
|
|
@@ -1623,7 +1894,7 @@ One month (since 1.16.0): a title between two round nav buttons, a weekday row a
|
|
|
1623
1894
|
| `.glass-calendar__head`, `__title`, `__nav` | Head row; title (ellipsis when tight); 32 px round nav buttons with an SVG chevron |
|
|
1624
1895
|
| `.glass-calendar__grid` | Seven columns, 4 px gap |
|
|
1625
1896
|
| `.glass-calendar__wd` | Weekday header cell, muted small caps |
|
|
1626
|
-
| `.glass-calendar__day` | Square day button; `[aria-pressed="true"]` chosen; `--today` warm border; `--other` dimmed; `:disabled` / `[aria-disabled="true"]` dimmed and unpickable |
|
|
1897
|
+
| `.glass-calendar__day` | Square day button; `[aria-pressed="true"]` chosen, on `--gl-color-primary-fill` where set (since 1.32.0), else the primary; `--today` warm border; `--other` dimmed; `:disabled` / `[aria-disabled="true"]` dimmed and unpickable |
|
|
1627
1898
|
| `.glass-calendar__marks`, `__mark` | 5 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` |
|
|
1628
1899
|
|
|
1629
1900
|
---
|
|
@@ -1657,6 +1928,190 @@ Choosing one image with a preview (since 1.16.0): a 72 px plate — the picture
|
|
|
1657
1928
|
|
|
1658
1929
|
---
|
|
1659
1930
|
|
|
1931
|
+
### 3.36 Tooltip
|
|
1932
|
+
|
|
1933
|
+
A short name or hint for a control on hover and focus (since 1.32.0): an icon-only button, the items of a rail, a row action. Small text on the popover's glass with its edge light, tinted far enough to read over anything (6.3:1 or more, white under a dark tooltip included), at most `--gl-tooltip-max-width` (240px) wide. `role="tooltip"`; the control points to it with `aria-describedby`, or with `aria-labelledby` where the tooltip is the control's only name. It opens in the top layer — `popover="hint"`, or `"manual"` where the browser does not know `hint` — and a script places it next to its control (`gkPlace()` in 3.25). GlassKit Elements' `<glk-tooltip>` brings the whole behaviour.
|
|
1934
|
+
|
|
1935
|
+
```html
|
|
1936
|
+
<button class="glass-pill" aria-labelledby="tip-archive">
|
|
1937
|
+
<svg viewBox="0 0 24 24"><!-- Icon --></svg>
|
|
1938
|
+
</button>
|
|
1939
|
+
<div class="glass-tooltip" id="tip-archive" role="tooltip" popover="manual">Archive</div>
|
|
1940
|
+
```
|
|
1941
|
+
|
|
1942
|
+
| Class | Description |
|
|
1943
|
+
|---|---|
|
|
1944
|
+
| `.glass-tooltip` | The tooltip: 13px medium text in `--gl-tooltip-color` (unset: the text colour) on `--gl-tooltip-bg` (unset: the theme's dark background at 94 %, blurred), wrapping at `--gl-tooltip-max-width` |
|
|
1945
|
+
| `.glass-tooltip[popover]` | In the top layer, `position: fixed` where the script puts it; fades in and out |
|
|
1946
|
+
|
|
1947
|
+
- **The behaviour is the script's**, all of it in `<glk-tooltip>`: shown on hover after a short delay (400ms) and at once on keyboard focus; on touch only after a long press, never on a tap; hidden on blur, on a press and on Escape — the focus stays, a dialog around stays open; the pointer may move from the control onto the tooltip without it closing (WCAG 1.4.13).
|
|
1948
|
+
- Text only: a tooltip never holds a link or a button — that is a popover.
|
|
1949
|
+
- Never the native `title` attribute instead: it shows neither on keyboard focus nor on touch.
|
|
1950
|
+
- `--gl-tooltip-offset` (8px) is the distance GlassKit Elements keeps from the control.
|
|
1951
|
+
|
|
1952
|
+
---
|
|
1953
|
+
|
|
1954
|
+
### 3.37 Menu
|
|
1955
|
+
|
|
1956
|
+
A list of actions behind a button (since 1.32.0): the overflow menu of a header, the actions of a table row. On the popover's surface, in the top layer and placed like the tooltip. Items are buttons with `role="menuitem"` — or `menuitemcheckbox` / `menuitemradio` with `aria-checked`, which shows the check mark — with an icon before the label and a hint at the end, such as a shortcut. For content (a form, a list of links, a text) take a popover; for commands a menu.
|
|
1957
|
+
|
|
1958
|
+
```html
|
|
1959
|
+
<button class="glass-btn glass-btn--secondary glass-btn--sm glass-btn--auto" id="view-button"
|
|
1960
|
+
aria-haspopup="menu" aria-expanded="false" popovertarget="view-menu">View</button>
|
|
1961
|
+
<div class="glass-menu" id="view-menu" role="menu" aria-labelledby="view-button" popover>
|
|
1962
|
+
<button class="glass-menu__item" role="menuitem" tabindex="-1">
|
|
1963
|
+
<span class="glass-menu__check"><svg viewBox="0 0 24 24"><polyline points="5 12 10 17 19 7"/></svg></span>
|
|
1964
|
+
<span class="glass-menu__icon"><svg viewBox="0 0 24 24"><!-- Icon --></svg></span>
|
|
1965
|
+
<span class="glass-menu__label">Duplicate</span>
|
|
1966
|
+
<span class="glass-menu__trailing">⌘D</span>
|
|
1967
|
+
</button>
|
|
1968
|
+
<button class="glass-menu__item" role="menuitemcheckbox" aria-checked="true" tabindex="-1">
|
|
1969
|
+
<span class="glass-menu__check"><svg viewBox="0 0 24 24"><polyline points="5 12 10 17 19 7"/></svg></span>
|
|
1970
|
+
<span class="glass-menu__label">Show archived</span>
|
|
1971
|
+
</button>
|
|
1972
|
+
<hr class="glass-menu__separator">
|
|
1973
|
+
<div role="group" aria-label="Sort by">
|
|
1974
|
+
<div class="glass-menu__group-label" aria-hidden="true">Sort by</div>
|
|
1975
|
+
<button class="glass-menu__item" role="menuitemradio" aria-checked="true" tabindex="-1">
|
|
1976
|
+
<span class="glass-menu__check"><svg viewBox="0 0 24 24"><polyline points="5 12 10 17 19 7"/></svg></span>
|
|
1977
|
+
<span class="glass-menu__label">Date</span>
|
|
1978
|
+
</button>
|
|
1979
|
+
</div>
|
|
1980
|
+
<hr class="glass-menu__separator">
|
|
1981
|
+
<button class="glass-menu__item glass-menu__item--danger" role="menuitem" tabindex="-1">
|
|
1982
|
+
<span class="glass-menu__check"><svg viewBox="0 0 24 24"><polyline points="5 12 10 17 19 7"/></svg></span>
|
|
1983
|
+
<span class="glass-menu__label">Delete</span>
|
|
1984
|
+
</button>
|
|
1985
|
+
</div>
|
|
1986
|
+
```
|
|
1987
|
+
|
|
1988
|
+
| Class | Description |
|
|
1989
|
+
|---|---|
|
|
1990
|
+
| `.glass-menu` | The panel, `role="menu"`, named by its button; 180–320px wide, scrolls past `min(70vh, 480px)` |
|
|
1991
|
+
| `.glass-menu[popover]` | In the top layer, `position: fixed` where the script puts it; scales and fades in |
|
|
1992
|
+
| `.glass-menu__item` | An item, 40px high: tinted on hover and `:focus`, a ring on `:focus-visible` — `.is-focused` / `.is-focus-visible` for a script that marks the focus itself |
|
|
1993
|
+
| `.glass-menu__item--danger` | Destructive: the error colour |
|
|
1994
|
+
| `.glass-menu__item[aria-disabled="true"]` / `.is-disabled` | Announced and reachable with the arrow keys, but dimmed and inert — use `aria-disabled`, not `disabled` |
|
|
1995
|
+
| `.glass-menu__check` | The check mark's room; shows on `[aria-checked="true"]` / `.is-checked` |
|
|
1996
|
+
| `.glass-menu__icon` | 18px icon before the label; empty or `hidden` takes no room |
|
|
1997
|
+
| `.glass-menu__label` | The label, one line with an ellipsis |
|
|
1998
|
+
| `.glass-menu__trailing` | A muted hint at the end, e.g. a shortcut |
|
|
1999
|
+
| `.glass-menu__separator` | A hairline between groups — an `<hr>`, or `role="separator"` |
|
|
2000
|
+
| `.glass-menu__group-label` | A small muted heading above a group (`role="group"` named the same) |
|
|
2001
|
+
|
|
2002
|
+
- **Line the labels up.** In a menu with checkable items every item carries a `.glass-menu__check`; it shows on the checked ones only. A menu without checkable items leaves it out.
|
|
2003
|
+
- **The keyboard is the script's** — the WAI-ARIA menu button, all of it in `<glk-menu>`: Enter, Space and Down on the button open the menu at its first item, Up at its last; Down and Up move and wrap, Home and End go to the ends, typing jumps to the next item that starts with the letters, Enter and Space choose, Escape closes and gives the focus back to the button, Tab closes and moves on. One tab stop: the items carry `tabindex="-1"`. The button's `aria-expanded` follows the menu.
|
|
2004
|
+
|
|
2005
|
+
---
|
|
2006
|
+
|
|
2007
|
+
### 3.38 Tree
|
|
2008
|
+
|
|
2009
|
+
Levels that open and close (since 1.32.0): the structure of an app, menus with submenus. A row per item — a twisty that turns when the item opens, an icon, the label, something at the end (a badge, a status, an action) — indented by `--gl-tree-indent` (20px) per level, with the item's children in a `__group` below it. No surface of its own: put it in a card or a sidebar.
|
|
2010
|
+
|
|
2011
|
+
```html
|
|
2012
|
+
<ul class="glass-tree" role="tree" aria-label="App structure">
|
|
2013
|
+
<li role="treeitem" aria-level="1" aria-expanded="true" aria-selected="false" aria-labelledby="node-menu" tabindex="-1">
|
|
2014
|
+
<div class="glass-tree__row is-expanded" style="--gl-tree-level: 1">
|
|
2015
|
+
<span class="glass-tree__twisty" aria-hidden="true"><svg viewBox="0 0 24 24"><polyline points="9 6 15 12 9 18"/></svg></span>
|
|
2016
|
+
<span class="glass-tree__icon" aria-hidden="true"><svg viewBox="0 0 24 24"><!-- Icon --></svg></span>
|
|
2017
|
+
<span class="glass-tree__label" id="node-menu">Main menu</span>
|
|
2018
|
+
<span class="glass-tree__trailing"><span class="glass-badge">2</span></span>
|
|
2019
|
+
</div>
|
|
2020
|
+
<ul class="glass-tree__group" role="group">
|
|
2021
|
+
<li role="treeitem" aria-level="2" aria-selected="true" aria-labelledby="node-services" tabindex="0">
|
|
2022
|
+
<div class="glass-tree__row is-leaf is-selected" style="--gl-tree-level: 2">
|
|
2023
|
+
<span class="glass-tree__twisty" aria-hidden="true"><svg viewBox="0 0 24 24"><polyline points="9 6 15 12 9 18"/></svg></span>
|
|
2024
|
+
<span class="glass-tree__label" id="node-services">Services</span>
|
|
2025
|
+
</div>
|
|
2026
|
+
</li>
|
|
2027
|
+
</ul>
|
|
2028
|
+
</li>
|
|
2029
|
+
</ul>
|
|
2030
|
+
```
|
|
2031
|
+
|
|
2032
|
+
| Class | Description |
|
|
2033
|
+
|---|---|
|
|
2034
|
+
| `.glass-tree` | The container, `role="tree"` with a name |
|
|
2035
|
+
| `.glass-tree__row` | An item's row, at least `--gl-tree-row-height` (36px) high, indented by (`--gl-tree-level` − 1) × `--gl-tree-indent`; set the level per row, 1 at the top |
|
|
2036
|
+
| `.glass-tree__row.is-expanded` | Open: the twisty turns down |
|
|
2037
|
+
| `.glass-tree__row.is-selected` | Chosen: raised glass like the active row of a sidebar, semibold, its icon in the accent |
|
|
2038
|
+
| `.glass-tree__row.is-leaf` | Without children: the twisty keeps its room, hidden |
|
|
2039
|
+
| `.glass-tree__row.is-loading` | Children on their way: the twisty turns into a small spinner (`aria-busy="true"` on the item) |
|
|
2040
|
+
| `.glass-tree__row.is-error` | Children that could not load: a "!" in the error colour in place of the twisty (since 1.32.0). Close the item, put the reason into its description (`aria-description`) and announce it; opening the item again tries once more |
|
|
2041
|
+
| `.glass-tree__row.is-disabled` | Dimmed, not-allowed cursor (`aria-disabled="true"` on the item) |
|
|
2042
|
+
| `.glass-tree__row.is-flash` | A 1.2s flash for an item that changed elsewhere, in `--gl-flash-color`, as on list items (since 1.32.0) |
|
|
2043
|
+
| `.glass-tree__row.is-focus-visible` | The focus ring, for a script that marks the focus itself. Where the `treeitem` takes the focus, `:focus-visible` on it already draws the ring on its row, not the browser's outline around the whole item (since 1.32.0); `:focus-visible` on the row itself works as well |
|
|
2044
|
+
| `.glass-tree__twisty` | The chevron; mirrored right to left |
|
|
2045
|
+
| `.glass-tree__icon` | 18px icon; empty or `hidden` takes no room |
|
|
2046
|
+
| `.glass-tree__label` | One line with an ellipsis |
|
|
2047
|
+
| `.glass-tree__trailing` | Muted, at the row's end |
|
|
2048
|
+
| `.glass-tree__group` | The children, `role="group"`; `hidden` while the item is closed |
|
|
2049
|
+
|
|
2050
|
+
- **ARIA on the items:** `role="treeitem"` with `aria-level`, `aria-expanded` only on items with children, `aria-selected`. Name each item by its label (`aria-labelledby`), or its children's text becomes part of its name.
|
|
2051
|
+
- **The keyboard is the script's**, the WAI-ARIA tree view, all of it in `<glk-tree>`: one tab stop (the selected item, else the first), Down and Up to the next and previous visible item, Right opens an item or moves to its first child, Left closes it or moves to its parent (mirrored right to left), Home and End, Enter and Space select — selection does not follow the focus — `*` opens every sibling, typing jumps.
|
|
2052
|
+
- **Children that load** when their item opens: `aria-expanded="false"` and the twisty before any child exists, `.is-loading` with `aria-busy="true"` while they come, `.is-error` where they did not. `<glk-tree>` brings it as `has-children`, `glk-tree-load` and `load-error`.
|
|
2053
|
+
- Reordering the items by drag and drop: 3.40.
|
|
2054
|
+
|
|
2055
|
+
---
|
|
2056
|
+
|
|
2057
|
+
### 3.39 Breadcrumbs
|
|
2058
|
+
|
|
2059
|
+
The path through nested levels (since 1.32.0): My app › Main menu › Services › Online booking. A `<nav aria-label="Breadcrumb">` around an `<ol>`; each crumb a link (or a button), the current level plain text with `aria-current="page"`. The separators are drawn by CSS between the items — hidden from assistive technology, mirrored right to left; never type `›` or `/` into the markup. A crumb wider than `--gl-breadcrumbs-crumb-width` (200px) ends in an ellipsis.
|
|
2060
|
+
|
|
2061
|
+
```html
|
|
2062
|
+
<nav class="glass-breadcrumbs" aria-label="Breadcrumb">
|
|
2063
|
+
<ol class="glass-breadcrumbs__list">
|
|
2064
|
+
<li class="glass-breadcrumbs__item"><a class="glass-breadcrumbs__crumb" href="/app">My app</a></li>
|
|
2065
|
+
<li class="glass-breadcrumbs__item glass-breadcrumbs__item--overflow"><button class="glass-breadcrumbs__crumb glass-breadcrumbs__overflow" type="button" aria-label="1 more level" aria-haspopup="menu" aria-expanded="false">…</button></li>
|
|
2066
|
+
<li class="glass-breadcrumbs__item"><a class="glass-breadcrumbs__crumb" href="/app/menu/services">Services</a></li>
|
|
2067
|
+
<li class="glass-breadcrumbs__item"><span class="glass-breadcrumbs__current" aria-current="page">Online booking</span></li>
|
|
2068
|
+
</ol>
|
|
2069
|
+
</nav>
|
|
2070
|
+
```
|
|
2071
|
+
|
|
2072
|
+
| Class | Description |
|
|
2073
|
+
|---|---|
|
|
2074
|
+
| `.glass-breadcrumbs` | The `<nav>`, named "Breadcrumb" |
|
|
2075
|
+
| `.glass-breadcrumbs__list` | The `<ol>`: one line, no wrapping |
|
|
2076
|
+
| `.glass-breadcrumbs__item` | A level; from the second on a CSS chevron before it |
|
|
2077
|
+
| `.glass-breadcrumbs__crumb` | A link or button to its level: muted, tinted on hover, a focus ring |
|
|
2078
|
+
| `.glass-breadcrumbs__current` | The level shown: plain text in the heading colour, semibold |
|
|
2079
|
+
| `.glass-breadcrumbs__overflow` | With `__crumb`: the "…" that stands for folded middle levels — a menu button (3.37) that lists them, named with the count ("2 more levels") |
|
|
2080
|
+
| `.glass-breadcrumbs__item--overflow` | On the `<li>` of the "…": it keeps its width where the path still does not fit (since 1.32.0) |
|
|
2081
|
+
| `.is-drop-target` / `.is-drop-refused` | On a crumb or the current level while a dragged item is over it: it takes the item into its level, or refuses it (3.40) |
|
|
2082
|
+
|
|
2083
|
+
GlassKit draws the path; `<glk-breadcrumbs>` in GlassKit Elements measures it, folds the middle levels into the "…" crumb where the path does not fit (the first crumb and the last two stay), shows a cut label in full in a tooltip, and makes the crumbs drop targets for a sortable list or tree.
|
|
2084
|
+
|
|
2085
|
+
---
|
|
2086
|
+
|
|
2087
|
+
### 3.40 Sorting (drag states)
|
|
2088
|
+
|
|
2089
|
+
The states of a drag that reorders a list or a tree (since 1.32.0). The dragged item stays where it was, faded; a raised copy follows the pointer in the top layer; a line shows where it lands, indented to the level it lands on; an item that takes it inside lights up, one that refuses it shows the error colour. The classes go on the rows — `.glass-list__item`, `.glass-tree__row`. The pointer, touch and keyboard handling, the announcements and the motion of the rows making room are GlassKit Elements' (`<glk-list sortable>`, `<glk-tree sortable>`).
|
|
2090
|
+
|
|
2091
|
+
```html
|
|
2092
|
+
<ul class="glass-list">
|
|
2093
|
+
<li class="glass-list__item is-sort-source">…</li>
|
|
2094
|
+
<li class="glass-list__item is-sort-before">
|
|
2095
|
+
<div class="glass-list__content"><div class="glass-list__title">Services</div></div>
|
|
2096
|
+
<span class="glass-sort__handle" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M5 9h14M5 15h14"/></svg></span>
|
|
2097
|
+
</li>
|
|
2098
|
+
</ul>
|
|
2099
|
+
<div class="glass-sort__ghost" popover="manual" aria-hidden="true">Pricing</div>
|
|
2100
|
+
```
|
|
2101
|
+
|
|
2102
|
+
| Class | Description |
|
|
2103
|
+
|---|---|
|
|
2104
|
+
| `.is-sort-source` | The dragged item where it was: faded to 0.4 |
|
|
2105
|
+
| `.glass-sort__ghost` | The raised copy that follows the pointer, in the top layer (`popover="manual"`); never takes the pointer, and is hidden while closed |
|
|
2106
|
+
| `.is-sort-before` / `.is-sort-after` | On the target row: a primary line above or below it, indented by `--gl-tree-level` |
|
|
2107
|
+
| `.is-sort-inside` | On a row that takes the item inside it — a tree item, a submenu: tint and ring |
|
|
2108
|
+
| `.is-sort-refused` | With one of the above: the target refuses the item — the error colour |
|
|
2109
|
+
| `.glass-sort__handle` | A grip: with one, only the handle starts a drag, so a tap on the row still chooses it, and a finger on it drags at once (`touch-action: none`) |
|
|
2110
|
+
|
|
2111
|
+
`--gl-sort-duration` (180ms) and `--gl-sort-easing` (`ease-out`) time the rows that make room and the drop gliding into place; nothing moves under `prefers-reduced-motion`. Never make dragging the only way: a keyboard path (Space picks up, the arrows move, Space drops, Escape cancels) and announcements in a live region belong to it — `<glk-list sortable>` and `<glk-tree sortable>` have both.
|
|
2112
|
+
|
|
2113
|
+
---
|
|
2114
|
+
|
|
1660
2115
|
## 4. Utility Classes
|
|
1661
2116
|
|
|
1662
2117
|
### Stack (Vertical)
|
|
@@ -1740,7 +2195,16 @@ Flexbox row with gap.
|
|
|
1740
2195
|
| `:checked` | Toggle, Checkbox, Radio (on the input) | Native checked state |
|
|
1741
2196
|
| `:focus` | Input, Textarea, Select, Range | Focus ring |
|
|
1742
2197
|
| `:disabled` | Input, Select, Textarea, Range (0.4); Button, Pill, Tab Bar Accessory, Modal action, list row, calendar arrow, Toggle, Checkbox, Radio (0.45) | Dimmed, not-allowed cursor, no hover (most since 1.21.2) |
|
|
1743
|
-
| `[aria-disabled="true"]` | `a.glass-btn` and the other buttons; date strip and calendar days | As `:disabled`, for elements that cannot be disabled — a link still navigates |
|
|
2198
|
+
| `[aria-disabled="true"]` | `a.glass-btn` and the other buttons; date strip and calendar days; `.glass-menu__item` | As `:disabled`, for elements that cannot be disabled — a link still navigates; a menu item stays reachable with the arrow keys |
|
|
2199
|
+
| `:popover-open` | `.glass-popover[popover]`, `.glass-tooltip[popover]`, `.glass-menu[popover]`, `.glass-sort__ghost` | Shown in the top layer, by `showPopover()` or a `popovertarget` button (since 1.32.0) |
|
|
2200
|
+
| `.is-checked` / `[aria-checked="true"]` | `.glass-menu__item` | Shows the check mark (since 1.32.0) |
|
|
2201
|
+
| `.is-focused` / `.is-focus-visible` | `.glass-menu__item`; `.is-focus-visible` also `.glass-tree__row` | Focus tint / ring, for a script that marks the focus itself (since 1.32.0) |
|
|
2202
|
+
| `.is-disabled` | `.glass-menu__item`, `.glass-tree__row` | Dimmed and inert, still announced (since 1.32.0) |
|
|
2203
|
+
| `.is-expanded`, `.is-selected`, `.is-leaf`, `.is-loading`, `.is-error` | `.glass-tree__row` | Open, chosen, without children, children loading, children that could not load (since 1.32.0) |
|
|
2204
|
+
| `.is-flash` | `.glass-list__item`, `.glass-tree__row` | A 1.2s flash for an item that changed elsewhere, in `--gl-flash-color` (since 1.32.0) |
|
|
2205
|
+
| `.is-drop-target` / `.is-drop-refused` | `.glass-breadcrumbs__crumb`, `.glass-breadcrumbs__current` | A dragged item over the crumb: taken into its level / refused (since 1.32.0) |
|
|
2206
|
+
| `.is-sort-source`, `-before`, `-after`, `-inside`, `-refused` | `.glass-list__item`, `.glass-tree__row` | The states of a drag that reorders (since 1.32.0, 3.40) |
|
|
2207
|
+
| `[aria-sort]` | `th` of `.glass-table` | The sorted column and its direction: the arrow of `__sort-icon` (since 1.32.0) |
|
|
1744
2208
|
|
|
1745
2209
|
---
|
|
1746
2210
|
|
|
@@ -2087,6 +2551,70 @@ Key points in this composition:
|
|
|
2087
2551
|
</div>
|
|
2088
2552
|
```
|
|
2089
2553
|
|
|
2554
|
+
### Back office (Sidebar + Breadcrumbs + Table + Menu)
|
|
2555
|
+
|
|
2556
|
+
Since 1.32.0: the navigation as a sidebar, the path above the content, a table with a sticky header and a menu per row.
|
|
2557
|
+
|
|
2558
|
+
```html
|
|
2559
|
+
<div class="glass-bg" style="display: grid; grid-template-columns: auto 1fr; height: 100dvh">
|
|
2560
|
+
<nav class="glass-tab-bar glass-tab-bar--vertical glass-tab-bar--droplet" aria-label="Main">
|
|
2561
|
+
<a class="glass-tab-bar__item is-active" href="/invoices" aria-current="page">
|
|
2562
|
+
<span class="glass-tab-bar__icon"><svg viewBox="0 0 24 24"><!-- Icon --></svg></span>
|
|
2563
|
+
<span class="glass-tab-bar__label">Invoices</span>
|
|
2564
|
+
</a>
|
|
2565
|
+
<a class="glass-tab-bar__item" href="/customers" aria-label="Customers, 3 new">
|
|
2566
|
+
<span class="glass-tab-bar__icon"><svg viewBox="0 0 24 24"><!-- Icon --></svg><span class="glass-tab-bar__badge">3</span></span>
|
|
2567
|
+
<span class="glass-tab-bar__label">Customers</span>
|
|
2568
|
+
</a>
|
|
2569
|
+
</nav>
|
|
2570
|
+
|
|
2571
|
+
<main class="gl-stack gl-stack--md gl-px" style="overflow-y: auto; padding-block: 24px">
|
|
2572
|
+
<nav class="glass-breadcrumbs" aria-label="Breadcrumb">
|
|
2573
|
+
<ol class="glass-breadcrumbs__list">
|
|
2574
|
+
<li class="glass-breadcrumbs__item"><a class="glass-breadcrumbs__crumb" href="/">Back office</a></li>
|
|
2575
|
+
<li class="glass-breadcrumbs__item"><span class="glass-breadcrumbs__current" aria-current="page">Invoices</span></li>
|
|
2576
|
+
</ol>
|
|
2577
|
+
</nav>
|
|
2578
|
+
<h1 class="glass-title">Invoices</h1>
|
|
2579
|
+
<div class="glass-table-frame">
|
|
2580
|
+
<div class="glass-table-wrap glass-table-wrap--sticky" style="--gl-table-max-height: calc(100dvh - 180px)">
|
|
2581
|
+
<table class="glass-table glass-table--sticky">
|
|
2582
|
+
<thead>
|
|
2583
|
+
<tr>
|
|
2584
|
+
<th aria-sort="descending"><button class="glass-table__sort" type="button">Date<svg class="glass-table__sort-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 19V5M6 11l6-6 6 6"/></svg></button></th>
|
|
2585
|
+
<th>Customer</th>
|
|
2586
|
+
<th class="glass-table__num">Amount</th>
|
|
2587
|
+
<th class="glass-table__actions" aria-label="Actions"></th>
|
|
2588
|
+
</tr>
|
|
2589
|
+
</thead>
|
|
2590
|
+
<tbody>
|
|
2591
|
+
<tr>
|
|
2592
|
+
<td data-label="Date">2026-10-27</td>
|
|
2593
|
+
<td data-label="Customer">Jungherz GmbH</td>
|
|
2594
|
+
<td class="glass-table__num" data-label="Amount">1,240.00</td>
|
|
2595
|
+
<td class="glass-table__actions">
|
|
2596
|
+
<button class="glass-btn glass-btn--tertiary glass-btn--sm glass-btn--auto" id="act-1042"
|
|
2597
|
+
aria-label="Actions for invoice 1042" aria-haspopup="menu" aria-expanded="false" popovertarget="menu-1042">…</button>
|
|
2598
|
+
<div class="glass-menu" id="menu-1042" role="menu" aria-labelledby="act-1042" popover>
|
|
2599
|
+
<button class="glass-menu__item" role="menuitem" tabindex="-1"><span class="glass-menu__label">Send again</span></button>
|
|
2600
|
+
<hr class="glass-menu__separator">
|
|
2601
|
+
<button class="glass-menu__item glass-menu__item--danger" role="menuitem" tabindex="-1"><span class="glass-menu__label">Cancel invoice</span></button>
|
|
2602
|
+
</div>
|
|
2603
|
+
</td>
|
|
2604
|
+
</tr>
|
|
2605
|
+
</tbody>
|
|
2606
|
+
</table>
|
|
2607
|
+
</div>
|
|
2608
|
+
</div>
|
|
2609
|
+
</main>
|
|
2610
|
+
</div>
|
|
2611
|
+
```
|
|
2612
|
+
|
|
2613
|
+
Key points:
|
|
2614
|
+
- One set of items for every layout: between two widths the `<nav>` takes `--rail`; on a phone the page drops its grid and the same `<nav>` drops `--vertical` for the bottom edge (with `.glass-bg--has-tab-bar`), or takes `--end` on a phone held open.
|
|
2615
|
+
- The header sticks to the wrap, which is as high as the page leaves (`--gl-table-max-height`).
|
|
2616
|
+
- The row's menu opens in the top layer, so the wrap's overflow does not cut it off; `gkPlace()` (3.25) puts it at its button, the keyboard is the page's script — or GlassKit Elements: `<glk-tab-bar orientation="vertical">`, `<glk-breadcrumbs>`, `<glk-table sticky-header>`, `<glk-menu>`.
|
|
2617
|
+
|
|
2090
2618
|
---
|
|
2091
2619
|
|
|
2092
2620
|
## 7. Rules & Common Mistakes
|
|
@@ -2108,7 +2636,9 @@ Key points in this composition:
|
|
|
2108
2636
|
8. **List dividers are automatic** – Never add a `<hr>` or divider element between `.glass-list__item`s. The divider is rendered via `::after` and respects `:has(.glass-list__leading)` for the inset.
|
|
2109
2637
|
9. **Popover toggle naming** – Never name your popover toggle JS function `togglePopover`. It collides with the native `HTMLElement.togglePopover()` method. Use a prefix like `gkTogglePopover`.
|
|
2110
2638
|
10. **`data-density`** – Like `data-theme`, on `<html>`: `compact` or absent. For a denser UI set the attribute or a density token, never `height` on the components.
|
|
2111
|
-
11. **Droplet needs its module** – `--droplet` on a tab bar or segmented row does nothing until `glasskit-droplet.js` attaches (`attachDroplets()`); recommend both together, and leave the `data-droplet*` attributes and `--gl-droplet
|
|
2639
|
+
11. **Droplet needs its module** – `--droplet` on a tab bar or segmented row does nothing until `glasskit-droplet.js` attaches (`attachDroplets()`); recommend both together, and leave the `data-droplet*` attributes and the `--gl-droplet-left/-right/-top/-bottom` properties to the module. The timing tokens (`--gl-droplet-duration` and the rest, since 1.32.0) are the project's to set.
|
|
2640
|
+
12. **One navigation, every layout** – a sidebar, an icon rail and a top bar are the tab bar with `--vertical`, `--rail` and `--top` (since 1.32.0). Keep one set of items and switch the modifiers; mark the open view with `aria-current="page"` and name the `<nav>`.
|
|
2641
|
+
13. **Top-layer panels need a script** – `.glass-popover[popover]`, `.glass-tooltip` and `.glass-menu` are drawn by GlassKit and placed by script (`gkPlace()` in 3.25); the keyboard of menu and tree is script as well (since 1.32.0). GlassKit Elements brings both.
|
|
2112
2642
|
|
|
2113
2643
|
### ❌ Common Mistakes
|
|
2114
2644
|
|
|
@@ -2126,13 +2656,27 @@ Key points in this composition:
|
|
|
2126
2656
|
| JS function named `togglePopover()` | Rename to `gkTogglePopover()` or similar to avoid native API clash |
|
|
2127
2657
|
| Putting `.is-open` on the trigger button instead of `.glass-popover` | The state class belongs on the popover element |
|
|
2128
2658
|
| Animating the selection of a tab bar or segmented row with your own script | `--droplet` plus `glasskit-droplet.js` (since 1.27.0) |
|
|
2129
|
-
| Setting `data-droplet
|
|
2659
|
+
| Setting `data-droplet*` or `--gl-droplet-left` / `-right` / `-top` / `-bottom` by hand | Let `attachDroplet()` set them; only the timing tokens are the project's (since 1.32.0) |
|
|
2130
2660
|
| Copying the tab bar's state rules onto a font icon, or overriding `stroke` on `.glass-tab-bar__icon svg` | Put the icon into `.glass-tab-bar__icon` as it is; set `--gl-tab-bar-color` / `--gl-tab-bar-hover-color` (since 1.28.0) |
|
|
2131
2661
|
| Overriding the tab label's `font-size` or the bar's `z-index` | `--gl-tab-bar-label-size`, `--gl-tab-bar-z-index` (since 1.28.0) |
|
|
2132
2662
|
| Restyling the chosen segmented option for a dark brand | `--gl-segmented-active-bg`, `-color`, `-shadow` (since 1.28.0) |
|
|
2133
2663
|
| A count in a segmented label, "Tickets (1)" | `.glass-segmented__badge` after the label, the count in the option's `aria-label` (since 1.29.0) |
|
|
2134
2664
|
| A tone on the option only to colour its count, or `--gl-segmented-badge-bg` / `-color` set to a state colour | `.glass-segmented__badge--error` (or `--primary`, `--success`, `--warning`) — no dot (since 1.31.0) |
|
|
2135
2665
|
| `--gl-radius-btn` set for pill-shaped buttons | `--gl-btn-radius: 9999px` — lists, toasts and the segmented control keep theirs (since 1.31.0) |
|
|
2666
|
+
| `--gl-color-primary` darkened until white text on the primary button passes | `--gl-btn-primary-bg` and `--gl-color-primary-fill` darken the fills alone, or switch the ink with `--gl-color-on-primary` (since 1.32.0, section 2) |
|
|
2667
|
+
| A rule on `.glass-radio__dot` to turn it dark with a dark ink | Nothing to do: the dot follows `--gl-color-on-primary` (since 1.32.0) |
|
|
2668
|
+
| A sidebar from `.glass-tab-bar` with its own `flex-direction`, `position` and `height` | `.glass-tab-bar--vertical`, with `--start` / `--end` for a fixed side, `--rail` for icons alone; `--top` for a top bar (since 1.32.0) |
|
|
2669
|
+
| `.glass-bg--has-tab-bar` next to a side bar | It pads the bottom edge only; pad the content on the bar's side yourself |
|
|
2670
|
+
| Overriding the drop's `transition` or `transform` | The `--gl-droplet-*` timing tokens (since 1.32.0) |
|
|
2671
|
+
| The native `title` attribute as the tooltip of an icon button | `.glass-tooltip` (3.36) — `title` shows neither on keyboard focus nor on touch |
|
|
2672
|
+
| Commands behind a button as plain buttons in a popover, without menu roles | `.glass-menu` with `role="menu"` / `menuitem` (3.37), the keyboard from `<glk-menu>` |
|
|
2673
|
+
| `›` or `/` typed between breadcrumbs | Leave them out — `.glass-breadcrumbs__item` draws the chevron, hidden from screen readers and mirrored right to left |
|
|
2674
|
+
| `--gl-radius-full` changed on the tab bar to round its drop and items | `--gl-tab-bar-item-radius` (since 1.33.0); the global token shapes every pill and badge |
|
|
2675
|
+
| A wrapper around a floating vertical bar that draws the rail's glass, with the mark and the accessory as its siblings | `--floating --vertical --start` with `--rail --labels`, the mark and `__accessory-item` in `__leading` (since 1.33.0) |
|
|
2676
|
+
| `--gl-space-2xs` / `--gl-font-size-xs` raised on a chip to make it taller | `.glass-badge--md` (since 1.33.0) |
|
|
2677
|
+
| A "Forgot password?" link positioned absolutely over the label row | `.glass-input-group--label-end` with `__label-end` after the field (since 1.33.0) |
|
|
2678
|
+
| `position: sticky` on `th` inside `.glass-table-wrap` | `.glass-table-wrap--sticky` + `.glass-table--sticky` (since 1.32.0) — a wrap that scrolls sideways is a scroll container in both directions |
|
|
2679
|
+
| `.glass-popover` without `[popover]` inside a card or a scrolling box that clips | Open it in the top layer with the `popover` attribute (since 1.32.0) |
|
|
2136
2680
|
| Overriding `height` of `.glass-btn`, `.glass-input` etc. for a denser UI | `data-density="compact"` on `<html>`, or set a density token — toggle thumb and label alignment follow the tokens, not a hand-set `height` |
|
|
2137
2681
|
|
|
2138
2682
|
---
|
|
@@ -2148,12 +2692,12 @@ Key points in this composition:
|
|
|
2148
2692
|
| Title | `.glass-title` | – |
|
|
2149
2693
|
| Card | `.glass-card` | `--glow` |
|
|
2150
2694
|
| Button | `.glass-btn` | `--primary`, `--secondary`, `--tertiary`, `--sm`, `--lg`, `--auto`, `:disabled` |
|
|
2151
|
-
| Badge | `.glass-badge` | `--primary`, `--success`, `--warning`, `--error`, `--interactive`, `--selected` |
|
|
2695
|
+
| Badge | `.glass-badge` | `--primary`, `--success`, `--warning`, `--error`, `--interactive`, `--selected`, `--md` |
|
|
2152
2696
|
| Avatar | `.glass-avatar` | `--sm`, `--lg` |
|
|
2153
2697
|
| Divider | `.glass-divider` | – |
|
|
2154
2698
|
| Status | `.glass-status` | – |
|
|
2155
2699
|
| Input | `.glass-input` | `--error`, `:disabled`; `.glass-input-wrap` with `__prefix` / `__suffix`, `--prefix` / `--suffix` |
|
|
2156
|
-
| Input Group | `.glass-input-group` |
|
|
2700
|
+
| Input Group | `.glass-input-group` | `--label-end` with `__label-end` |
|
|
2157
2701
|
| Label | `.glass-label` | – |
|
|
2158
2702
|
| Hint | `.glass-hint` | `--error` |
|
|
2159
2703
|
| Textarea | `.glass-textarea` | `:disabled` |
|
|
@@ -2166,12 +2710,17 @@ Key points in this composition:
|
|
|
2166
2710
|
| Progress | `.glass-progress` | `--sm`, `--lg`, `--success`, `--error` |
|
|
2167
2711
|
| Modal | `.glass-modal-overlay` | `.is-active` |
|
|
2168
2712
|
| Toast | `.glass-toast` | `--success`, `--error`, `--warning`, `.is-visible`, `__action`, `__close` |
|
|
2169
|
-
| Tab Bar | `.glass-tab-bar` | `.is-active` on items, `__icon`, `__label`, `__badge`, `--floating`, `--droplet` |
|
|
2713
|
+
| Tab Bar | `.glass-tab-bar` | `.is-active` on items, `__icon`, `__label`, `__badge`, `__leading`, `__trailing`, `__accessory-item`, `__accessory-label`, `--floating`, `--droplet`, `--vertical`, `--start`, `--end`, `--rail`, `--labels`, `--top`; `.glass-tab-bar-dock--vertical`, `-dock--start` / `--end` |
|
|
2170
2714
|
| Accordion | `.glass-accordion` | `.is-open` on items |
|
|
2171
|
-
| List | `.glass-list` | `--flush`, `--bare`, `__item--interactive`, `__item--center`, `__item--danger`, `__item--accent`, `__leading--lg`, `__subtitle--wrap`, `__value`, `__section-header` |
|
|
2172
|
-
| Popover | `.glass-popover` | `--top`, `--start`, `--end`, `.is-open` |
|
|
2715
|
+
| List | `.glass-list` | `--flush`, `--bare`, `__item--interactive`, `__item--center`, `__item--danger`, `__item--accent`, `__leading--lg`, `__subtitle--wrap`, `__value`, `__section-header`, `.is-flash` on items |
|
|
2716
|
+
| Popover | `.glass-popover` | `--top`, `--start`, `--end`, `.is-open`, `[popover]`, `[data-side]` |
|
|
2717
|
+
| Tooltip | `.glass-tooltip` | `[popover]` |
|
|
2718
|
+
| Menu | `.glass-menu` | `[popover]`, `__item`, `__item--danger`, `__check`, `__icon`, `__label`, `__trailing`, `__separator`, `__group-label`, `[aria-checked]` / `.is-checked`, `[aria-disabled]` / `.is-disabled`, `.is-focused`, `.is-focus-visible` |
|
|
2719
|
+
| Tree | `.glass-tree` | `__row`, `__twisty`, `__icon`, `__label`, `__trailing`, `__group`, `.is-expanded`, `.is-selected`, `.is-leaf`, `.is-loading`, `.is-error`, `.is-disabled`, `.is-flash`, `.is-focus-visible` |
|
|
2720
|
+
| Breadcrumbs | `.glass-breadcrumbs` | `__list`, `__item`, `__item--overflow`, `__crumb`, `__current`, `__overflow`, `.is-drop-target`, `.is-drop-refused` |
|
|
2721
|
+
| Sorting | `.is-sort-source` | `.is-sort-before`, `-after`, `-inside`, `-refused`; `.glass-sort__ghost`, `.glass-sort__handle` |
|
|
2173
2722
|
| Skeleton | `.glass-skeleton` | `__line`, `__line--title` |
|
|
2174
|
-
| Table | `.glass-table` | `-wrap`, `__num`, `__muted` |
|
|
2723
|
+
| Table | `.glass-table` | `-wrap`, `-wrap--sticky`, `-frame`, `__num`, `__muted`, `__sort`, `__sort-icon`, `__actions`, `__empty`, `--sticky`, `--scrolls`, `--list`, `[aria-sort]` |
|
|
2175
2724
|
| Prose | `.glass-prose` | – |
|
|
2176
2725
|
| Segmented | `.glass-segmented` | `--full`, `--scroll`, `--wrap`, `--icons`, `--droplet`, `__item`, `__item--success`/`--warning`/`--error`, `__dot`, `__icon`, `__badge`, `[aria-pressed]` |
|
|
2177
2726
|
| Steps | `.glass-steps` | `__item`, `__item--done`, `__item--current`, `__num`, `__label`, `__line` |
|
|
@@ -2299,6 +2848,10 @@ The opposite case — a primary dark enough for white button text, too dark for
|
|
|
2299
2848
|
}
|
|
2300
2849
|
```
|
|
2301
2850
|
|
|
2851
|
+
White on the filled accents — the primary button, the chosen day, the current step — reaches AA without a new brand colour since 1.32.0: `--gl-btn-primary-bg` and `--gl-color-primary-fill` darken the fills alone, and `--gl-color-on-primary` switches the ink, which the radio's dot follows now as well. The recipes, with the measured ratios, are in section 2 (Role Colors).
|
|
2852
|
+
|
|
2853
|
+
The drop of `--droplet` rows is timed by tokens too (since 1.32.0, 3.4): `--gl-droplet-duration`, `-easing`, `-trail-duration`, `-trail-delay`, `-trail-easing`, `-lift`, `-lift-duration`, `-settle-duration`, `-settle-easing`, `-lens-duration`, `-lens-easing`.
|
|
2854
|
+
|
|
2302
2855
|
Overriding `--gl-color-success` / `--gl-color-error` is enough on its own: fill, border,
|
|
2303
2856
|
text and glow of every state component are derived from those tokens. Only if you want
|
|
2304
2857
|
a different ink than the derived one do you need to touch `--gl-color-{state}-on-surface`.
|