@codenhub/styles 0.5.0 → 0.7.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/NOTICE +18 -16
- package/README.es.md +61 -0
- package/README.md +27 -22
- package/README.pt-BR.md +61 -0
- package/dist/aesthetics/chunky-tile.css +1 -1
- package/dist/aesthetics/cyber.css +1 -1
- package/dist/aesthetics/glass.css +1 -1
- package/dist/aesthetics/index.css +2 -2
- package/dist/aesthetics/neobrutalism.css +1 -1
- package/dist/aesthetics/pixel.css +1 -1
- package/dist/aesthetics/sketch.css +1 -1
- package/dist/components.css +2 -2
- package/dist/index.css +2 -2
- package/dist/native.css +2 -2
- package/dist/palette.css +1 -1
- package/dist/theme.css +2 -2
- package/dist/tw/aesthetics/chunky-tile.css +120 -62
- package/dist/tw/aesthetics/cyber.css +102 -40
- package/dist/tw/aesthetics/glass.css +371 -19
- package/dist/tw/aesthetics/index.css +2 -1
- package/dist/tw/aesthetics/neobrutalism.css +121 -33
- package/dist/tw/aesthetics/pixel.css +111 -16
- package/dist/tw/aesthetics/sketch.css +100 -28
- package/dist/tw/box.css +69 -28
- package/dist/tw/components/button.css +35 -14
- package/dist/tw/components/feedback.css +61 -58
- package/dist/tw/components/form.css +255 -142
- package/dist/tw/components/index.css +4 -9
- package/dist/tw/components/surface.css +80 -68
- package/dist/tw/components/tooltip.css +75 -41
- package/dist/tw/elevation.css +14 -22
- package/dist/tw/index.css +15 -19
- package/dist/tw/intent.css +35 -27
- package/dist/tw/native.css +22 -12
- package/dist/tw/palette.css +14 -11
- package/dist/tw/presentation.css +16 -30
- package/dist/tw/reset.css +36 -43
- package/dist/tw/surface.css +11 -12
- package/dist/tw/theme.css +87 -103
- package/dist/tw/utilities/content.css +311 -200
- package/dist/tw/utilities/layout.css +41 -37
- package/docs/accessibility.md +104 -58
- package/docs/changelog/0.1.1.md +1 -0
- package/docs/changelog/0.2.0.md +1 -0
- package/docs/changelog/0.3.0.md +1 -0
- package/docs/changelog/0.4.0.md +1 -0
- package/docs/changelog/0.5.0.md +8 -3
- package/docs/changelog/0.6.0.md +53 -0
- package/docs/changelog/0.7.0.md +50 -0
- package/docs/changelog/index.md +2 -0
- package/docs/concepts.md +188 -46
- package/docs/es/accessibility.md +150 -0
- package/docs/es/concepts.md +212 -0
- package/docs/es/index.md +104 -0
- package/docs/es/integrating/astro.md +35 -0
- package/docs/es/integrating/index.md +47 -0
- package/docs/es/integrating/nextjs.md +67 -0
- package/docs/es/integrating/svelte.md +45 -0
- package/docs/es/integrating/tailwind.md +78 -0
- package/docs/es/integrating/vue.md +31 -0
- package/docs/es/integrating/without-a-bundler.md +115 -0
- package/docs/es/setup.md +180 -0
- package/docs/es/usage/aesthetics.md +276 -0
- package/docs/es/usage/buttons.md +131 -0
- package/docs/es/usage/composing.md +164 -0
- package/docs/es/usage/content-and-layout.md +215 -0
- package/docs/es/usage/customizing.md +298 -0
- package/docs/es/usage/feedback.md +153 -0
- package/docs/es/usage/forms.md +231 -0
- package/docs/es/usage/index.md +29 -0
- package/docs/es/usage/solo.md +84 -0
- package/docs/es/usage/theming.md +296 -0
- package/docs/es/usage/tooltips.md +127 -0
- package/docs/index.md +89 -21
- package/docs/integrating/astro.md +3 -4
- package/docs/integrating/index.md +18 -13
- package/docs/integrating/nextjs.md +4 -5
- package/docs/integrating/svelte.md +5 -4
- package/docs/integrating/tailwind.md +29 -8
- package/docs/integrating/vue.md +3 -4
- package/docs/integrating/without-a-bundler.md +114 -0
- package/docs/pt-BR/accessibility.md +150 -0
- package/docs/pt-BR/concepts.md +212 -0
- package/docs/pt-BR/index.md +104 -0
- package/docs/pt-BR/integrating/astro.md +35 -0
- package/docs/pt-BR/integrating/index.md +47 -0
- package/docs/pt-BR/integrating/nextjs.md +67 -0
- package/docs/pt-BR/integrating/svelte.md +45 -0
- package/docs/pt-BR/integrating/tailwind.md +78 -0
- package/docs/pt-BR/integrating/vue.md +31 -0
- package/docs/pt-BR/integrating/without-a-bundler.md +115 -0
- package/docs/pt-BR/setup.md +180 -0
- package/docs/pt-BR/usage/aesthetics.md +276 -0
- package/docs/pt-BR/usage/buttons.md +131 -0
- package/docs/pt-BR/usage/composing.md +164 -0
- package/docs/pt-BR/usage/content-and-layout.md +215 -0
- package/docs/pt-BR/usage/customizing.md +298 -0
- package/docs/pt-BR/usage/feedback.md +153 -0
- package/docs/pt-BR/usage/forms.md +231 -0
- package/docs/pt-BR/usage/index.md +29 -0
- package/docs/pt-BR/usage/solo.md +84 -0
- package/docs/pt-BR/usage/theming.md +296 -0
- package/docs/pt-BR/usage/tooltips.md +127 -0
- package/docs/setup.md +134 -91
- package/docs/usage/aesthetics.md +102 -65
- package/docs/usage/buttons.md +108 -40
- package/docs/usage/composing.md +105 -92
- package/docs/usage/content-and-layout.md +159 -127
- package/docs/usage/customizing.md +112 -43
- package/docs/usage/feedback.md +135 -70
- package/docs/usage/forms.md +184 -99
- package/docs/usage/index.md +18 -14
- package/docs/usage/solo.md +83 -0
- package/docs/usage/theming.md +260 -119
- package/docs/usage/tooltips.md +103 -42
- package/llms-full.txt +2465 -1272
- package/llms.txt +25 -17
- package/package.json +28 -35
- package/dist/tw/components/loader.css +0 -117
|
@@ -1,24 +1,32 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Customizing
|
|
3
|
-
description:
|
|
4
|
-
order:
|
|
3
|
+
description: Lookup for presentation and material tokens, aesthetic knobs, the six public component variables, the generated palette, and the helpers for building your own components.
|
|
4
|
+
order: 9
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Customizing
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
This is a lookup page for changing the package beyond its classes. [Theming](./theming.md) covers colors and the foundation tokens; this page covers the rest:
|
|
10
|
+
|
|
11
|
+
- [Presentation tokens](#presentation-tokens): how much of an intent a component shows.
|
|
12
|
+
- [Material tokens](#material-tokens): what a component is made of.
|
|
13
|
+
- [Aesthetic tokens](#aesthetic-tokens): the knobs each aesthetic exposes.
|
|
14
|
+
- [Component variables](#component-variables): the six variables a single component reads.
|
|
15
|
+
- [Generated palette](#generated-palette): fixed color values for code that cannot load the package.
|
|
16
|
+
- [Composition helpers](#composition-helpers): the classes to build a component of your own from.
|
|
10
17
|
|
|
11
18
|
## Presentation tokens
|
|
12
19
|
|
|
13
20
|
Presentation tokens describe _how much_ of an intent a component shows, never _which_ intent it shows. They are unitless numbers and percentages, so they carry no color and inherit safely: a container sets them once and every component below resolves them against its own intent.
|
|
14
21
|
|
|
15
|
-
| Token | Purpose
|
|
16
|
-
| ----------------- |
|
|
17
|
-
| `--ui-fill` | Percentage of the intent color mixed into the background.
|
|
18
|
-
| `--ui-fg-on-fill` | Percentage blended from the intent
|
|
19
|
-
| `--ui-border` | Percentage of the intent color
|
|
22
|
+
| Token | Purpose | Default |
|
|
23
|
+
| ----------------- | --------------------------------------------------------------------------------------------------- | ----------------------------------- |
|
|
24
|
+
| `--ui-fill` | Percentage of the intent color mixed into the background. | The component's default; see below. |
|
|
25
|
+
| `--ui-fg-on-fill` | Percentage blended from the intent's strong tone toward its contrast color. | The component's default. |
|
|
26
|
+
| `--ui-border` | Percentage of the intent's border color in the border. | The component's default. |
|
|
27
|
+
| `--hover-step` | Added to the resting fill under the pointer, in `--intent-hover`. Set it on `:root` or any element. | `14%` |
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
Unset, each component uses its own default, listed in [Composing → Component defaults](./composing.md#component-defaults). The presentation classes set the first three to the values in [Composing → Presentation](./composing.md#presentation). There are no hover tokens per presentation: hover is always the resting fill plus `--hover-step`, up to 100%.
|
|
22
30
|
|
|
23
31
|
No fill class writes `--ui-border` and no edge class writes `--ui-fill`. A filled box with no line is `.solid.edgeless`, and `.solid.edged` renders the same box: the line fades out as the fill fills in, so even a neutral fill, capped and translucent, shows through its own border as one coat.
|
|
24
32
|
|
|
@@ -36,7 +44,9 @@ A computed color therefore reaches the page as a resolved `color-mix` result rat
|
|
|
36
44
|
|
|
37
45
|
Material tokens describe what a component is _made of_ rather than which intent it shows or how strongly. They control shape, borders, shadows, translucency, filters, and transforms.
|
|
38
46
|
|
|
39
|
-
Components read each with a fallback, so leaving them unset
|
|
47
|
+
Components read each with a fallback, so leaving them unset gives the default look. Set on a container, they restyle everything inside it. The one exception is `--ui-elevation`, which does not inherit, so it reaches only the element it is set on; see [Composing → Elevation](./composing.md#elevation).
|
|
48
|
+
|
|
49
|
+
Shadow geometry is split into parts with no color in them, so they inherit safely. Tokens that take a color, such as `--ui-ink` and `--ui-surface-shadow`, may include their own.
|
|
40
50
|
|
|
41
51
|
| Token | Purpose | Fallback |
|
|
42
52
|
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
|
|
@@ -46,14 +56,15 @@ Components read each with a fallback, so leaving them unset produces the default
|
|
|
46
56
|
| `--ui-radius` | A complete control radius, used as written: overrides the corner, the step, and the pattern. | Computed from the corner |
|
|
47
57
|
| `--ui-radius-surface` | A complete surface radius, used as written. | Computed from the corner |
|
|
48
58
|
| `--ui-scale` | Overrides the size step the size and padding classes set. | The step |
|
|
49
|
-
| `--ui-corner-shape` | What every corner draws: `round`,
|
|
59
|
+
| `--ui-corner-shape` | What every corner draws: `round`, `bevel` for a straight cut, or `squircle` for a continuous curve. Chromium only today. | `round` |
|
|
50
60
|
| `--ui-radius-pill` | Corner for what is fully round by default: badges, switches, progress, the tooltip icon; `.btn.pill` and `.radio` read it with no fallback but full. | `--ui-radius`, `--ui-corner`, then full |
|
|
51
|
-
| `--ui-radius-tight` | Complete radius for chips
|
|
61
|
+
| `--ui-radius-tight` | Complete radius for chips, such as a checkbox, `.kbd`, or `.code`, when set. Unset, a small computed default. | `min(--ui-radius or --ui-corner, small)` |
|
|
52
62
|
| `--ui-line-style` | Style of every line a component draws: `solid`, `dashed`, `dotted`, or `double` (3px wide or more). | `solid` |
|
|
53
63
|
| `--ui-border-width` | Edge thickness. | `--border-width` |
|
|
54
64
|
| `--ui-border-max` | Ceiling on computed edge width. | `100px` |
|
|
55
65
|
| `--ui-ink` | Neutral line color when no intent is set. | `--color-border` |
|
|
56
66
|
| `--ui-control-ink` | Neutral line color of fields, selects, checkboxes, radios, and switches when no intent is set. | `--ui-ink`, then `--color-control-border` |
|
|
67
|
+
| `--ui-rule-ink` | Neutral line color of a table's frame and rules when no intent is set. | `--ui-ink`, then `--color-border` |
|
|
57
68
|
| `--ui-rule` | Lines inside a table. Unset draws the head and foot boundaries only; `0%` draws none; `100%` rules every row. | unset |
|
|
58
69
|
| `--ui-shadow-x` | Shadow horizontal offset. | `0px` |
|
|
59
70
|
| `--ui-shadow-y` | Shadow vertical offset. | `0px` |
|
|
@@ -68,13 +79,13 @@ Components read each with a fallback, so leaving them unset produces the default
|
|
|
68
79
|
| `--ui-active-translate-x` | Distance a press travels into the element's depth; `-y` beside it. Scaled like the shadow. | `0px` |
|
|
69
80
|
| `--ui-shadow-ink` | Percentage of shadow color taken from intent ink. | `0%` |
|
|
70
81
|
| `--ui-halo-blur` | Blur of a halo around the element; `--ui-halo-spread` beside it. Elevation does not scale it. | `0px` |
|
|
71
|
-
| `--ui-halo-ink` | The halo's share of the intent
|
|
82
|
+
| `--ui-halo-ink` | The halo's share of the intent color, over nothing. Unset, there is no halo. | Unset |
|
|
72
83
|
| `--ui-shadow-edge` | Declared, even empty, when the shadow is the element's edge rather than its depth. Read for presence. | Unset |
|
|
73
|
-
| `--ui-elevation` | Unitless multiplier over shadow geometry.
|
|
84
|
+
| `--ui-elevation` | Unitless multiplier over shadow geometry. Does not inherit. | `1` |
|
|
74
85
|
| `--ui-surface-shadow` | Complete multi-layer shadow accepted by surfaces only. | Unset |
|
|
75
|
-
| `--ui-surface-ground` | Ground a surface sits on.
|
|
76
|
-
| `--ui-bg-alpha` | Multiplier over fill
|
|
77
|
-
| `--ui-backdrop` | Backdrop filter accepted by surfaces only.
|
|
86
|
+
| `--ui-surface-ground` | Ground a surface, or a default or `.soft` table, sits on. | `--color-background` |
|
|
87
|
+
| `--ui-bg-alpha` | Multiplier over every fill, `.solid` included. No shipped aesthetic sets it. | `1` |
|
|
88
|
+
| `--ui-backdrop` | Backdrop filter accepted by surfaces, and by a default or `.soft` table, only. | `none` |
|
|
78
89
|
| `--ui-surface-image` | A painted layer over a surface's plate: any `background-image` value. Surfaces only. | `none` |
|
|
79
90
|
| `--ui-hover-transform` | Transform while an interactive element is hovered. | `none` |
|
|
80
91
|
| `--ui-clip` | Structural component silhouette. | `none` |
|
|
@@ -83,7 +94,7 @@ Components read each with a fallback, so leaving them unset produces the default
|
|
|
83
94
|
| `--ui-label-weight` | Label weight of `.btn` (and, with `/native`, a bare `<button>`) and `.badge`. | Semibold on a button, bold on a badge |
|
|
84
95
|
| `--ui-label-tracking` | Label letter spacing. Unset, the label inherits it. | Unset |
|
|
85
96
|
| `--ui-label-case` | Label `text-transform`. | `none` on a button; inherited on a badge |
|
|
86
|
-
| `--ui-label-shadow` | Label `text-shadow`, written without a
|
|
97
|
+
| `--ui-label-shadow` | Label `text-shadow`, written without a color so it takes the label's own. | `none` on a button; inherited on a badge |
|
|
87
98
|
|
|
88
99
|
```html
|
|
89
100
|
<section style="--ui-corner: 0; --ui-border-width: 3px">
|
|
@@ -102,23 +113,23 @@ Which corners take the corner is its own choice. `.cut-diagonal` keeps the top-l
|
|
|
102
113
|
|
|
103
114
|
### Lines, layers, and labels
|
|
104
115
|
|
|
105
|
-
`--ui-line-style` reaches every line a component draws: the box's edge, the progress track, and dividers and table rules. `--ui-rule-style` optionally overrides just dividers and table rules, without changing the box edge; sketch uses it for dashed accents. A dashed or dotted line keeps its
|
|
116
|
+
`--ui-line-style` reaches every line a component draws: the box's edge, the progress track, and dividers and table rules. `--ui-rule-style` optionally overrides just dividers and table rules, without changing the box edge; sketch uses it for dashed accents. A dashed or dotted line keeps its color, so it keeps its contrast. A `double` line needs a width of 3px or more to draw two lines.
|
|
106
117
|
|
|
107
|
-
`--ui-halo-*` is light rather than depth
|
|
118
|
+
`--ui-halo-*` is light rather than depth: a glow in the element's own intent color. Elevation does not scale it, and `.flat` leaves it on. It appears only when its ink is set.
|
|
108
119
|
|
|
109
120
|
`--ui-surface-image` lays any `background-image` over a surface's plate: cards, panels, alerts, and tooltips, not controls. Whoever sets it owns the contrast of the text over it, and your own `background-image` on a surface still wins.
|
|
110
121
|
|
|
111
|
-
`--ui-label-*` treats the label of a button or a badge: weight, tracking, case, and a text shadow. Write the shadow without a
|
|
122
|
+
`--ui-label-*` treats the label of a button or a badge: weight, tracking, case, and a text shadow. Write the shadow without a color, such as `0 0 6px`, so it takes the label's own color and cannot lower its contrast. Your own `font-*`, `tracking-*`, and case utilities still win.
|
|
112
123
|
|
|
113
|
-
Under forced
|
|
124
|
+
Under forced colors each of these draws its plain version: a solid line, no halo, no painted layer, and no label shadow. The silhouette and the ring below go too. Forced colors remove every box shadow, so `--ui-clip`, `--ui-clip-tight`, `--ui-border-max`, and `--ui-shadow-edge` are cleared and a component draws its real border at `--ui-border-width`.
|
|
114
125
|
|
|
115
126
|
### Shape and ring composition
|
|
116
127
|
|
|
117
|
-
Clipping removes borders, outlines, and outer shadows. An aesthetic that uses a clip can replace the border with an inset shadow by setting `--ui-shadow-inset` and the four shadow geometry parts. Set `--ui-border-max: 0px` when that ring replaces the component border. Focusable components restore the clipped focus outline through `--ui-focus-inset
|
|
128
|
+
Clipping removes borders, outlines, and outer shadows. An aesthetic that uses a clip can replace the border with an inset shadow by setting `--ui-shadow-inset` and the four shadow geometry parts. Set `--ui-border-max: 0px` when that ring replaces the component border. Focusable components restore the clipped focus outline through `--ui-focus-inset`: an inset layer of that width in `--focus-ring`, with a 2px line of `--color-background` inside it so focus still shows on a component filled with the ring's own color.
|
|
118
129
|
|
|
119
|
-
A clip is not the only way to cut a corner. `--ui-corner-shape: bevel` draws the corner the radius sets as a straight cut instead of an arc, and the border, outer shadow, focus outline, and backdrop all follow it
|
|
130
|
+
A clip is not the only way to cut a corner. `--ui-corner-shape: bevel` draws the corner the radius sets as a straight cut instead of an arc, and the border, outer shadow, focus outline, and backdrop all follow it. A beveled element therefore keeps its glow and its line, where a clipped one loses both. `.cyber` uses it. Engines without `corner-shape` ignore it and draw the radius round, so an aesthetic that bevels should square its radius under `@supports not (corner-shape: bevel)`. A bevel on a full radius cuts to points: a radio, a `.btn.pill`, and anything reading `--ui-radius-pill` become diamonds or pointed hexagons.
|
|
120
131
|
|
|
121
|
-
`--ui-radius` accepts any `border-radius` value and is used as written, so it can place the corner per side: `10px 0` cuts only top-left and bottom-right. The pill and chip corners are separate tokens. An unset chip corner computes a small default from `--ui-radius`, then `--ui-corner`, capped at `--radius-small`; an explicit `--ui-radius-tight` is used as written, even for a per-corner or elliptical value. Aesthetic and consumer overrides can therefore give a chip a larger or more irregular shape. `.btn.pill` takes `--ui-radius-pill` ahead of the other radii; under sketch it takes
|
|
132
|
+
`--ui-radius` accepts any `border-radius` value and is used as written, so it can place the corner per side: `10px 0` cuts only top-left and bottom-right. The pill and chip corners are separate tokens. An unset chip corner computes a small default from `--ui-radius`, then `--ui-corner`, capped at `--radius-small`; an explicit `--ui-radius-tight` is used as written, even for a per-corner or elliptical value. Aesthetic and consumer overrides can therefore give a chip a larger or more irregular shape. `.btn.pill` takes `--ui-radius-pill` ahead of the other radii; under sketch it takes an uneven hand-drawn pill outline whose ends stay the same size. An explicit `--ui-radius-pill` on that button still wins.
|
|
122
133
|
|
|
123
134
|
Declare `--ui-shadow-edge` when that ring _is_ the border. The ring then takes the element's edge color, which carries the edge axis as its alpha, so `.edged` draws it and `.edgeless` does not — the same answer a real border gives. Without it the ring paints on every component the aesthetic reaches and the edge classes have no effect. Use `--ui-shadow-ink` instead when the shadow is depth cast in the intent's own ink, such as a hard offset slab, which an `.edgeless` element still gets.
|
|
124
135
|
|
|
@@ -148,8 +159,8 @@ The shipped [aesthetic classes](./aesthetics.md) set material tokens for you. On
|
|
|
148
159
|
| Token | Aesthetic | Purpose | Default |
|
|
149
160
|
| --------------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
150
161
|
| `--neo-offset` | `.neobrutalism` | Hard shadow offset and distance the press travels. | `4px` |
|
|
151
|
-
| `--glass-radius` | `.glass`
|
|
152
|
-
| `--glass-radius-surface` | `.glass`
|
|
162
|
+
| `--glass-radius` | `.glass`, `.glass-liquid` | Control corner radius. `1rem` under `.glass-liquid`. | `0.75rem` |
|
|
163
|
+
| `--glass-radius-surface` | `.glass`, `.glass-liquid` | Surface corner radius. `1.5rem` under `.glass-liquid`. | `1rem` |
|
|
153
164
|
| `--pixel-unit` | `.pixel` | One pixel of the grid. The corner cut and the ring are one. | `4px` |
|
|
154
165
|
| `--font-pixel` | `.pixel` | Consumer-supplied pixel font stack. | Falls back to the monospace stack |
|
|
155
166
|
| `--tile-radius` | `.chunky-tile` | Corner radius, on controls and surfaces alike. | `0.75rem` |
|
|
@@ -159,13 +170,13 @@ The shipped [aesthetic classes](./aesthetics.md) set material tokens for you. On
|
|
|
159
170
|
| `--cyber-shape` | `.cyber` | Where controls take the cut: any `border-radius` value. | `<cut> 0` (top-left, bottom-right) |
|
|
160
171
|
| `--cyber-shape-surface` | `.cyber` | Where surfaces take the cut: any `border-radius` value. | `0 <cut>` (top-right, bottom-left) |
|
|
161
172
|
| `--cyber-glow` | `.cyber` | Blur of the glow. | `8px` |
|
|
162
|
-
| `--cyber-ink` | `.cyber` | Neutral line and glow
|
|
173
|
+
| `--cyber-ink` | `.cyber` | Neutral line and glow color, where no intent sets one. | Theme ink (near-black, near-white) |
|
|
163
174
|
| `--font-cyber` | `.cyber` | Consumer-supplied technical font stack. | Falls back to the monospace stack |
|
|
164
175
|
| `--sketch-radius` | `.sketch` | Control outline radius: any `border-radius` value. | Irregular box outline with sibling variation |
|
|
165
176
|
| `--sketch-radius-surface` | `.sketch` | Surface container outline radius: any `border-radius` value. | Sharp irregular square outline with sibling variation |
|
|
166
177
|
| `--sketch-radius-rounded` | `.sketch`, `.sketch-rounded` | Rounded control outline radius: expressive elliptical contour with sibling variation. | `26px 10px 24px 11px / 12px 23px 11px 20px` with sibling variation |
|
|
167
178
|
| `--sketch-radius-surface-rounded` | `.sketch`, `.sketch-rounded` | Rounded surface container outline radius: expressive elliptical contour with sibling variation. | `38px 16px 36px 17px / 16px 34px 17px 32px` with sibling variation |
|
|
168
|
-
| `--sketch-radius-pill` | `.sketch` |
|
|
179
|
+
| `--sketch-radius-pill` | `.sketch` | Radius of a pill button's outline: an uneven hand-drawn pill whose ends stay the same size. | `24px 16px 23px 17px / 17px 21px 16px 20px` with sibling variation |
|
|
169
180
|
| `--font-sketch` | `.sketch` | Consumer-supplied handwriting font stack. | Falls back to `cursive` |
|
|
170
181
|
|
|
171
182
|
Every aesthetic's knobs reach the same way: each knob is _read_ with its default as a `var()` fallback rather than declared, so it resolves once into a private on the aesthetic's own class (`--_pixel-unit`, `--_neo-offset`, `--_tile-radius`, `--_tile-lift`, and so on). Set a knob on the element carrying the aesthetic class, or on any ancestor including `:root`:
|
|
@@ -184,15 +195,19 @@ Every aesthetic's knobs reach the same way: each knob is _read_ with its default
|
|
|
184
195
|
</html>
|
|
185
196
|
```
|
|
186
197
|
|
|
187
|
-
Knobs and material tokens reach in opposite directions
|
|
198
|
+
Knobs and material tokens reach in opposite directions. A knob is read once, at the element with the aesthetic class, and the result passes down. So set a knob on that element or on one above it; set on an element inside the aesthetic, it changes nothing, because the value has already been read.
|
|
199
|
+
|
|
200
|
+
`--ui-radius` and the other material tokens are read by each component as it draws. They work on the element they are set on and everything inside it, which is how you round one card differently from its neighbors without touching the knob.
|
|
188
201
|
|
|
189
|
-
Shipped aesthetics set the shared material tokens above. Every shipped aesthetic sets `--ui-ink` for its neutral line. `.glass` and `.chunky-tile`
|
|
202
|
+
Shipped aesthetics set the shared material tokens above. Every shipped aesthetic sets `--ui-ink` for its neutral line. Every shipped aesthetic also sets `--ui-control-ink`: `.glass` and `.chunky-tile` to a line of their own, heavier than their surfaces', and the others to `--color-control-border`, since their ink is near-black or near-white and a resting checkbox outlined in it would look checked. `.glass` sets `--ui-rule-ink` too, so a table's lines read on its plate; the others clear it. Intent classes still override the intent slots on each component.
|
|
190
203
|
|
|
191
|
-
The same knobs tune each aesthetic's [solo class](./
|
|
204
|
+
The same knobs tune each aesthetic's [solo class](./solo.md), which reads them on its own element.
|
|
192
205
|
|
|
193
206
|
## Generated palette
|
|
194
207
|
|
|
195
|
-
`@codenhub/styles/palette` is a generated
|
|
208
|
+
`@codenhub/styles/palette` is a generated stylesheet of fixed colors: for every intent and presentation, the background, text, and border color a component would draw, as flat `--palette-*` custom properties. It is for code that cannot load this package's stylesheet, such as a library that lists `@codenhub/styles` as an optional peer, but wants to match it. Where you can load the stylesheet, use the components instead.
|
|
209
|
+
|
|
210
|
+
**The values are a snapshot of the shipped colors.** They were computed from the package's default theme when it was built, and they do not change when you override a token. If you set `--color-primary` to your brand color, `--palette-primary-solid-bg` is still the shipped near-black. Code that must follow your theme has to read the `--color-*` tokens, which means loading `@codenhub/styles/theme`.
|
|
196
211
|
|
|
197
212
|
```css
|
|
198
213
|
@import "@codenhub/styles/palette";
|
|
@@ -206,23 +221,77 @@ The same knobs tune each aesthetic's [solo class](./aesthetics.md#solo-classes),
|
|
|
206
221
|
}
|
|
207
222
|
```
|
|
208
223
|
|
|
209
|
-
Every value is
|
|
224
|
+
Every value is a finished color, never a reference to another variable, so the file needs nothing else loaded.
|
|
210
225
|
|
|
211
226
|
Naming: `--palette-<intent>-<presentation>-<slot>`, where `<intent>` is one of the seven published intents (`neutral`, `primary`, `secondary`, `success`, `warning`, `destructive`, `info`) and `<presentation>` is `solid`, `soft`, or `ghost`. `<slot>` is `bg`, `fg`, or `edge`. Two qualifiers layer on only where they apply:
|
|
212
227
|
|
|
213
|
-
- A ground qualifier
|
|
214
|
-
-
|
|
228
|
+
- A ground qualifier, `page` or `subtle`, before the slot. It appears only on the `bg` and `edge` of `.soft` and `.ghost`, because a `.solid` fill covers its ground and the text color never depends on it.
|
|
229
|
+
- No qualifier is the transparent ground of `.badge` and `.btn`: `--palette-success-soft-bg`.
|
|
230
|
+
- `page` is the ground of `.alert`, `--color-background`: `--palette-success-soft-page-bg`.
|
|
231
|
+
- `subtle` is the ground of `.pre`, `.code`, `.kbd`, and `.tooltip-bubble`, the intent's own `--intent-subtle`: `--palette-success-soft-subtle-bg`.
|
|
232
|
+
- A `-hover` suffix, on `bg` and `edge` only, because the text color does not change on hover: `--palette-success-soft-page-bg-hover`.
|
|
233
|
+
|
|
234
|
+
Light values are set on `:root`. Dark values apply under `.dark`, `.theme-dark`, or `[data-theme="dark"]` on the element or an element above it, the same selectors the package's theme uses. The light values also apply under `.light`, `.theme-light`, and `[data-theme="light"]`, so the nearest explicit theme wins: a light area inside a dark one reads the light values.
|
|
235
|
+
|
|
236
|
+
The file does not follow `prefers-color-scheme`. Code that uses the palette on its own already switches themes itself, so it sets one of those classes or attributes.
|
|
237
|
+
|
|
238
|
+
Three more tokens have no intent, presentation, ground, or hover: `--palette-border`, `--palette-surface`, and `--palette-text`, fixed values of `--color-border`, `--color-surface`, and `--color-text`. They are for things that are not intent-colored, such as a container's border, a dialog's background, and its text.
|
|
239
|
+
|
|
240
|
+
## Component variables
|
|
241
|
+
|
|
242
|
+
Six variables are read by a single component and are supported inputs. Every other variable a component declares, such as `--surface-padding`, `--field-gap`, `--switch-*`, `--table-*`, or `--quote-*`, is internal and may change in any release.
|
|
243
|
+
|
|
244
|
+
| Variable | Element | Value | Default | Effect | Where to set it |
|
|
245
|
+
| -------------------- | -------------- | ---------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
246
|
+
| `--progress-value` | `.progress` | A percentage, `0%` to `100%` | `0%` | Width of the filled part. Not clamped; a value without `%` is invalid and shows empty. | The bar, or any element around it. |
|
|
247
|
+
| `--progress-color` | `.progress` | A color | The intent color | Color of the filled part and of the `.active` shimmer. | The bar, or any element around it. |
|
|
248
|
+
| `--progress-surface` | `.progress` | A color | The intent color at the presentation's fill: 12% by default | Color of the track. | The bar, or any element around it. |
|
|
249
|
+
| `--progress-edge` | `.progress` | A color | The intent's border color at the presentation's border: none by default | Color of the track's border. It shows only where the track has a border width, such as with `.edged`. | The bar, or any element around it. |
|
|
250
|
+
| `--input-group-gap` | `.input-group` | A length | `0.5rem` | Space between the control and its icon or text. | The `.input-group` itself. The group declares the default, so a value on a parent is ignored. |
|
|
251
|
+
| `--tooltip-linger` | `.tooltip` | A time | `300ms` | How long the bubble stays after the pointer leaves the trigger. | The `.tooltip` itself. The wrapper declares the default, so a value on a parent is ignored. |
|
|
252
|
+
|
|
253
|
+
```html
|
|
254
|
+
<div class="progress" role="meter" aria-label="Storage used" aria-valuemin="0" aria-valuemax="100" aria-valuenow="92" style="--progress-value: 92%; --progress-color: var(--color-warning)"></div>
|
|
255
|
+
|
|
256
|
+
<div class="input-group" style="--input-group-gap: 0">
|
|
257
|
+
<span>app.example.com/u/</span>
|
|
258
|
+
<input class="ipt" id="profile-url" aria-label="Profile address" />
|
|
259
|
+
</div>
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
The examples in context are in [Feedback → Show progress](./feedback.md#show-progress), [Forms → Add an icon or a fixed prefix](./forms.md#add-an-icon-or-a-fixed-prefix), and [Tooltips → Hover, linger, and Escape](./tooltips.md#hover-linger-and-escape).
|
|
263
|
+
|
|
264
|
+
## Composition helpers
|
|
265
|
+
|
|
266
|
+
To build a component the package does not ship, such as a segmented control or a filter chip, compose it from the same classes the package's components are built from. With compiled CSS, write them as classes; with Tailwind source, you can also `@apply` them.
|
|
215
267
|
|
|
216
|
-
|
|
268
|
+
| Class | What it gives an element |
|
|
269
|
+
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
270
|
+
| `box` | The painted box: background, text color, border, corner, shadow, the aesthetic's material, the focus ring, and the disabled look. It reads intent, presentation, aesthetic, and elevation. |
|
|
271
|
+
| `box-hover` | The hover color, for something pressed rather than typed into. Add it with `box`. |
|
|
272
|
+
| `box-active` | The press: a slight shrink, or the aesthetic's own press. Add it with `box`. |
|
|
273
|
+
| `surface` | `box` with a surface's defaults: no fill and a border, the surface corner, and the aesthetic's surface background, blur, and shadow, as on a card. |
|
|
274
|
+
| `text-control` | `box` with a text field's defaults: no fill and a border, the capped fill and border rules, placeholder color, a border that changes on hover and focus, and the invalid state. |
|
|
275
|
+
|
|
276
|
+
Filter chips for the members list, one pressed and one not:
|
|
277
|
+
|
|
278
|
+
```html
|
|
279
|
+
<button class="box box-hover box-active neutral soft edgeless" type="button" aria-pressed="true" style="padding: 0.25rem 0.75rem; border-radius: 999px">Admins</button>
|
|
280
|
+
|
|
281
|
+
<button class="box box-hover box-active neutral ghost edgeless" type="button" aria-pressed="false" style="padding: 0.25rem 0.75rem; border-radius: 999px">Owners</button>
|
|
282
|
+
```
|
|
217
283
|
|
|
218
|
-
|
|
284
|
+
`box` does not read `aria-pressed`, so the pressed chip looks pressed only because it has `.soft`. When your code changes `aria-pressed`, change the presentation class with it: `.soft` when pressed, `.ghost` when not.
|
|
219
285
|
|
|
220
|
-
|
|
286
|
+
What to give each one:
|
|
221
287
|
|
|
222
|
-
|
|
288
|
+
- **`box` needs a fill and an edge class.** It has no defaults of its own, so with no `.solid`, `.soft`, or `.ghost` and no `.edged` or `.edgeless`, on the element or a container, it draws nothing. `surface` and `text-control` have defaults and work alone.
|
|
289
|
+
- **Name the intent.** A `box` element takes the intent of the nearest element around it that has one, unlike the package's components. Put `.neutral` or an intent class on it.
|
|
290
|
+
- **Size and spacing are yours.** None of the helpers sets padding, width, or height; `text-control` does not set the 2.5rem height that `.ipt` adds.
|
|
291
|
+
- **So are behavior and semantics.** Use a real `<button>`, `<input>`, or `<a href>`, or add the role and keyboard handling yourself, and set states such as `aria-pressed` or `aria-invalid`. `box` draws the disabled look for `disabled`, `.disabled`, `aria-disabled="true"`, and `data-disabled`, but only the `disabled` attribute stops input.
|
|
223
292
|
|
|
224
|
-
|
|
293
|
+
Do not set or read the `--_`-prefixed variables these helpers use internally; they change between releases.
|
|
225
294
|
|
|
226
|
-
|
|
295
|
+
## Next
|
|
227
296
|
|
|
228
|
-
|
|
297
|
+
[Content and layout](./content-and-layout.md) lists the layout helpers, the type scale, surfaces, tables, and content chips.
|
package/docs/usage/feedback.md
CHANGED
|
@@ -1,87 +1,152 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Feedback
|
|
3
|
-
description:
|
|
4
|
-
order:
|
|
3
|
+
description: A saving button, alerts, badges, loading placeholders, and progress bars, and what your code must keep in sync with them.
|
|
4
|
+
order: 3
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Feedback
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
These variants retain their embedded SVG animations normally. Under `prefers-reduced-motion: reduce`, loader CSS substitutes a corresponding static mask. This fallback is part of focused loader, button, and components imports; it does not depend on the global reset. See [Accessibility](../accessibility.md).
|
|
37
|
-
|
|
38
|
-
Loader size modifiers:
|
|
39
|
-
|
|
40
|
-
| Class | Size |
|
|
41
|
-
| -------- | -------------------- |
|
|
42
|
-
| _(none)_ | Default (`1.75rem`). |
|
|
43
|
-
| `.sm` | Small (`1.25rem`). |
|
|
44
|
-
| `.lg` | Large (`2.25rem`). |
|
|
45
|
-
|
|
46
|
-
Alerts, badges, progress bars, skeletons, and loaders accept `.primary`, `.secondary`, `.success`, `.warning`, `.destructive`, and `.info`. Without an intent, they use the text palette, except `.loader`, which keeps `currentColor` so it matches whatever content surrounds it.
|
|
47
|
-
|
|
48
|
-
Skeletons, loaders, and dividers are indicators: they read intent but ignore fill and edge [presentation](./composing.md#presentation). `.progress` is not one of them — its track reads both, `.soft.edgeless` by default; only the moving value fill stays intent-colored at full strength regardless of presentation. `.solid` is unsupported on the track, and `.ghost.edgeless` renders but is discouraged, since neither leaves the track a visible frame. See [Composing → Component axis reference](./composing.md#component-axis-reference) for the full table.
|
|
9
|
+
The profile form can be submitted, but nothing tells the user what happened. This page adds the screen's feedback: a Save button that shows it is working, an alert when the save succeeds, a badge on the plan card, a placeholder while the profile loads, and bars for storage use and a data export. The package draws each of these; your code decides when they appear, updates their values, and makes sure screen readers hear about them.
|
|
10
|
+
|
|
11
|
+
## Show that the form is saving
|
|
12
|
+
|
|
13
|
+
There is no loading class. A saving button is a disabled button with a spinning icon:
|
|
14
|
+
|
|
15
|
+
```html
|
|
16
|
+
<button class="btn primary" type="submit" disabled>
|
|
17
|
+
<i class="ic-lucide-loader-circle ic-anim-spin" aria-hidden="true"></i>
|
|
18
|
+
Saving…
|
|
19
|
+
</button>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The spinner comes from `@codenhub/icons`, which this package does not load. Load it once, as [Buttons → Loading icons](./buttons.md#loading-icons) shows; with compiled CSS that is:
|
|
23
|
+
|
|
24
|
+
```css
|
|
25
|
+
@import "@codenhub/icons";
|
|
26
|
+
@import "@codenhub/icons/lucide";
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`ic-anim-spin` rotates the icon and stops when the user asks the system for reduced motion. The animated `svg-spinners` family in `@codenhub/icons` is different: its artwork keeps moving under that preference. Either icon takes the button's text color.
|
|
30
|
+
|
|
31
|
+
Disabling the button stops a second click from submitting twice. Whether to keep or replace the label is up to you; the package has no way to hide it. A changing button label is not reliably announced, so tell screen reader users the outcome with a status message, as the next section does.
|
|
32
|
+
|
|
33
|
+
## Confirm the result with an alert
|
|
34
|
+
|
|
35
|
+
When the save succeeds, show an alert above the form:
|
|
49
36
|
|
|
50
37
|
```html
|
|
51
|
-
<
|
|
38
|
+
<div class="alert success" role="status">Profile saved.</div>
|
|
52
39
|
```
|
|
53
40
|
|
|
54
|
-
|
|
41
|
+
`role="status"` makes screen readers announce the text politely, after what they are reading. For an error the user must act on, use `role="alert"`, which interrupts:
|
|
42
|
+
|
|
43
|
+
```html
|
|
44
|
+
<div class="alert destructive" role="alert">Your changes were not saved. Check your connection and try again.</div>
|
|
45
|
+
```
|
|
55
46
|
|
|
56
|
-
|
|
47
|
+
Screen readers announce a live region when its content changes, so render the region empty when the page loads and put the message into it, rather than inserting a new alert element with the text already inside. The package adds no role, timing, or dismiss button; those are yours.
|
|
57
48
|
|
|
58
|
-
|
|
49
|
+
An alert is a row with a 0.75rem gap, so an icon placed before the message is spaced automatically. `.alert-icon` sizes an icon to 1.25rem and aligns it with the first line of text:
|
|
59
50
|
|
|
60
51
|
```html
|
|
61
|
-
<div class="alert
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
<svg class="alert-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
|
65
|
-
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" />
|
|
66
|
-
<path d="M12 9v4" />
|
|
67
|
-
<path d="M12 17h.01" />
|
|
68
|
-
</svg>
|
|
69
|
-
Review required.
|
|
52
|
+
<div class="alert warning" role="status">
|
|
53
|
+
<i class="alert-icon ic-lucide-triangle-alert" aria-hidden="true"></i>
|
|
54
|
+
Your card expires next month. Update it to keep your plan.
|
|
70
55
|
</div>
|
|
71
|
-
<div class="alert destructive ghost edged" role="alert">Deployment failed.</div>
|
|
72
|
-
<span class="badge warning">Queued</span>
|
|
73
|
-
<span class="badge success solid">Live</span>
|
|
74
|
-
<span class="badge info soft">Draft</span>
|
|
75
|
-
<span class="loader" aria-hidden="true"></span>
|
|
76
|
-
<span class="loader dots-wave" aria-hidden="true"></span>
|
|
77
|
-
<span class="loader dots-fade" aria-hidden="true"></span>
|
|
78
|
-
<span class="loader bars-wave" aria-hidden="true"></span>
|
|
79
|
-
<span class="loader pulse-ring sm" aria-hidden="true"></span>
|
|
80
|
-
<span class="loader dots-grow lg" aria-hidden="true"></span>
|
|
81
|
-
<div class="progress" role="progressbar" aria-label="Upload progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="64" style="--progress-value: 64%"></div>
|
|
82
|
-
<div class="progress secondary active" role="progressbar" aria-label="Upload progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="64" style="--progress-value: 64%"></div>
|
|
83
|
-
<div class="progress primary ghost edged" role="progressbar" aria-label="Upload progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="64" style="--progress-value: 64%"></div>
|
|
84
|
-
<div class="progress info indeterminate" role="progressbar" aria-label="Loading" aria-valuemin="0" aria-valuemax="100"></div>
|
|
85
56
|
```
|
|
86
57
|
|
|
87
|
-
|
|
58
|
+
Any icon element works: a class from an icon set, an inline `<svg>`, or an `<img>`. `@codenhub/icons` sizes its glyphs in a rule no class can outrank, so `.alert-icon` also sets that set's `--ic-size`. To resize an alert icon, write your own rule that sets `width`, `height`, and, for `@codenhub/icons`, `--ic-size`.
|
|
59
|
+
|
|
60
|
+
### How alerts look
|
|
61
|
+
|
|
62
|
+
With no presentation class, an alert is soft and edged: a light tint of its intent, intent-colored text, and a border. Presentation classes change that like on any component, such as `.alert.primary.solid` for a filled banner.
|
|
63
|
+
|
|
64
|
+
An alert with no intent is an exception. It has no tint at rest; it uses `--color-foreground`, the quiet background tone one step off the page, the same as a neutral `.card.soft` or `.panel`. An alert with `.primary`, `.secondary`, `.success`, `.warning`, `.destructive`, or `.info` keeps its tint. Only those six classes count here: an alert with an intent class you defined yourself is treated as having no intent; see [Theming → Your own intent](./theming.md#your-own-intent).
|
|
65
|
+
|
|
66
|
+
## Label the plan with a badge
|
|
67
|
+
|
|
68
|
+
A badge is a small pill for a status or a count:
|
|
69
|
+
|
|
70
|
+
```html
|
|
71
|
+
<section class="card soft primary stack tight" aria-labelledby="plan-title">
|
|
72
|
+
<div class="cluster between">
|
|
73
|
+
<h2 class="text-label" id="plan-title">Current plan</h2>
|
|
74
|
+
<span class="badge success">Active</span>
|
|
75
|
+
</div>
|
|
76
|
+
<p class="text-title-sm">Team, billed yearly</p>
|
|
77
|
+
</section>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
A badge is soft with no border by default, and takes the same intent and presentation classes as a button: `.badge.warning` for "Payment due", `.badge.info.solid` for a filled "New". Unlike an alert, a badge with no intent keeps its light tint, because it has no border, and without the tint it would disappear into the text around it.
|
|
81
|
+
|
|
82
|
+
## Show a placeholder while loading
|
|
83
|
+
|
|
84
|
+
While the profile card waits for data, show gray blocks where the text will be:
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<section class="card stack" aria-busy="true" aria-labelledby="profile-title">
|
|
88
|
+
<h2 class="text-title-sm" id="profile-title">Profile</h2>
|
|
89
|
+
<p class="visually-hidden">Loading your profile…</p>
|
|
90
|
+
<div class="stack tight" aria-hidden="true">
|
|
91
|
+
<div class="skeleton" style="height: 2.5rem"></div>
|
|
92
|
+
<div class="skeleton" style="width: 60%"></div>
|
|
93
|
+
</div>
|
|
94
|
+
</section>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
A `.skeleton` fills the width of its container and is at least 1rem tall. It has no size or shape of its own: use a block element such as a `<div>`, and set its width and height to match the content it stands in for. An empty inline element such as `<span class="skeleton">` has no size and does not appear.
|
|
98
|
+
|
|
99
|
+
A skeleton takes an intent but ignores presentation. With no intent, it is a light gray tinted by the surrounding text color. It shows a moving shimmer that stops when the user asks for reduced motion.
|
|
100
|
+
|
|
101
|
+
Mark the blocks `aria-hidden="true"`, because they mean nothing to a screen reader. Say that the content is loading in text instead, as the visually hidden paragraph does, and remove `aria-busy` once the content is in place.
|
|
102
|
+
|
|
103
|
+
## Show progress
|
|
104
|
+
|
|
105
|
+
The storage card shows how much space is used, and the danger zone's "Export data first" button starts an export that takes a while. Both are `.progress` bars:
|
|
106
|
+
|
|
107
|
+
```html
|
|
108
|
+
<div class="progress" role="meter" aria-label="Storage used" aria-valuemin="0" aria-valuemax="100" aria-valuenow="48" aria-valuetext="48 GB of 100 GB" style="--progress-value: 48%"></div>
|
|
109
|
+
|
|
110
|
+
<div class="progress primary" role="progressbar" aria-label="Export progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="20" style="--progress-value: 20%"></div>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`--progress-value` is the width of the filled part, as a percentage of the track. It is 0% when unset.
|
|
114
|
+
|
|
115
|
+
- **Write it with `%`.** `--progress-value: 48` without a unit is not a valid width, and the bar shows empty.
|
|
116
|
+
- **Nothing is clamped or checked.** Above 100%, the fill is cut off at the end of the track and looks full; a negative value is not a valid width either. Keep the value between 0% and 100% in your code.
|
|
117
|
+
- **The visual value and the announced value are separate.** The bar's width comes from `--progress-value`; what a screen reader announces comes from `aria-valuenow`. The package does not connect them, so update both together.
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
function setExportProgress(bar, percent) {
|
|
121
|
+
const value = Math.min(100, Math.max(0, Math.round(percent)));
|
|
122
|
+
bar.classList.remove("indeterminate");
|
|
123
|
+
bar.style.setProperty("--progress-value", `${value}%`);
|
|
124
|
+
bar.setAttribute("aria-valuenow", String(value));
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
When you do not know how far along the work is, such as while the export is being prepared, use `.indeterminate`. A bar about a third of the track wide sweeps from start to end, again and again, and `--progress-value` is ignored. Remove `aria-valuenow`, because there is no known value to announce:
|
|
129
|
+
|
|
130
|
+
```html
|
|
131
|
+
<div class="progress primary indeterminate" role="progressbar" aria-label="Preparing export"></div>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`.active` adds a shimmer over the track of a determinate bar, to show that work is still happening between updates. Both animations stop when the user asks for reduced motion; an indeterminate bar then rests with its fill at the start.
|
|
135
|
+
|
|
136
|
+
### How progress bars look
|
|
137
|
+
|
|
138
|
+
The fill is the intent color at full strength, or `currentColor` with no intent. The track is soft and edgeless by default: a light tint with no border.
|
|
139
|
+
|
|
140
|
+
The default track is faint. Against the page it measures about 1.1:1 to 1.3:1, below the 3:1 that WCAG 1.4.11 asks of the parts of a graphic needed to understand it. When the track's extent matters, use `.ghost.edged` with an intent class, which draws an outline around it in the intent's color. With no intent the outline is a light gray that measures below 3:1; [Accessibility → Progress outlines](../accessibility.md#progress-outlines) has the measurements and what to do for a neutral bar. `.solid` is not supported on the track, because the fill and the track would be the same color. `.ghost.edgeless` renders, but leaves the track with no visible frame.
|
|
141
|
+
|
|
142
|
+
To change the colors of the fill, the track, or its border without changing the intent, set `--progress-color`, `--progress-surface`, or `--progress-edge` on the bar or any element around it. They and `--progress-value` are listed in [Customizing → Component variables](./customizing.md#component-variables).
|
|
143
|
+
|
|
144
|
+
## Animation that keeps running
|
|
145
|
+
|
|
146
|
+
Skeletons, `.active` shimmers, indeterminate bars, and spinners animate for as long as they are on the page. The package stops its own animations when the user asks the system for reduced motion, but that is not the only requirement. WCAG 2.2.2 asks that motion which starts automatically, lasts more than five seconds, and is shown alongside other content can be paused, stopped, or hidden by the user, unless the motion is essential.
|
|
147
|
+
|
|
148
|
+
A loading indicator shown while the user cannot do anything else, and that would confuse them if it were missing, counts as essential. A shimmer or spinner that keeps moving next to content the user is working with, such as a decorative "live" shimmer on a card, does not. Remove those as soon as their work is done, or give the user a control that stops them.
|
|
149
|
+
|
|
150
|
+
## Next
|
|
151
|
+
|
|
152
|
+
The screen now reports what it is doing. [Tooltips](./tooltips.md) adds short help text beside a form field.
|