@codenhub/styles 0.0.4 → 0.1.1
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/LICENSE +201 -201
- package/NOTICE +27 -0
- package/README.md +22 -116
- package/dist/aesthetics/chunky-tile.css +1 -0
- package/dist/aesthetics/glass.css +1 -0
- package/dist/aesthetics/index.css +2 -0
- package/dist/aesthetics/neobrutalism.css +1 -0
- package/dist/aesthetics/pixel.css +1 -0
- package/dist/components.css +2 -2
- package/dist/index.css +2 -2
- package/dist/native.css +2 -0
- package/dist/theme.css +2 -2
- package/dist/tw/aesthetics/chunky-tile.css +109 -0
- package/dist/tw/aesthetics/glass.css +66 -0
- package/dist/tw/aesthetics/index.css +9 -0
- package/dist/tw/aesthetics/neobrutalism.css +63 -0
- package/dist/tw/aesthetics/pixel.css +88 -0
- package/dist/tw/box.css +206 -0
- package/dist/tw/components/button.css +108 -0
- package/dist/tw/components/feedback.css +163 -0
- package/dist/tw/components/form.css +599 -0
- package/dist/tw/components/index.css +28 -0
- package/dist/tw/components/loader.css +122 -0
- package/dist/tw/components/surface.css +122 -0
- package/dist/tw/components/tooltip.css +132 -0
- package/dist/tw/elevation.css +46 -0
- package/dist/tw/index.css +27 -0
- package/dist/tw/intent.css +209 -0
- package/dist/tw/native.css +187 -0
- package/dist/tw/presentation.css +77 -0
- package/dist/tw/reset.css +129 -0
- package/dist/tw/theme.css +223 -0
- package/dist/tw/typography.css +34 -0
- package/dist/tw/utilities/content.css +361 -0
- package/dist/tw/utilities/index.css +6 -0
- package/dist/tw/utilities/layout.css +107 -0
- package/docs/accessibility.md +92 -0
- package/docs/changelog/0.1.0.md +37 -0
- package/docs/changelog/0.1.1.md +10 -0
- package/docs/changelog/index.md +10 -0
- package/docs/concepts.md +68 -0
- package/docs/index.md +35 -0
- package/docs/integrating/astro.md +35 -0
- package/docs/integrating/index.md +41 -0
- package/docs/integrating/nextjs.md +67 -0
- package/docs/integrating/svelte.md +43 -0
- package/docs/integrating/tailwind.md +56 -0
- package/docs/integrating/vue.md +31 -0
- package/docs/setup.md +96 -0
- package/docs/usage/aesthetics.md +120 -0
- package/docs/usage/buttons.md +58 -0
- package/docs/usage/composing.md +143 -0
- package/docs/usage/content-and-layout.md +175 -0
- package/docs/usage/customizing.md +148 -0
- package/docs/usage/feedback.md +79 -0
- package/docs/usage/forms.md +135 -0
- package/docs/usage/index.md +24 -0
- package/docs/usage/theming.md +154 -0
- package/docs/usage/tooltips.md +39 -0
- package/llms-full.txt +1676 -0
- package/llms.txt +26 -0
- package/package.json +176 -33
- package/src/components/button.css +0 -155
- package/src/components/feedback.css +0 -214
- package/src/components/form.css +0 -303
- package/src/components/index.css +0 -9
- package/src/components/loader.css +0 -56
- package/src/components/surface.css +0 -6
- package/src/components/tooltip.css +0 -60
- package/src/index.css +0 -7
- package/src/overrides.css +0 -76
- package/src/theme.css +0 -234
- package/src/typography.css +0 -30
- package/src/utilities.css +0 -40
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Buttons
|
|
3
|
+
description: Button classes, intents, sizes, and states.
|
|
4
|
+
order: 5
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Buttons
|
|
8
|
+
|
|
9
|
+
Use `.btn` with one optional intent class, one optional fill class, one optional edge class, optional size class, and optional state. See [Composing](./composing.md) for how the intent, presentation, and aesthetic axes combine on any component.
|
|
10
|
+
|
|
11
|
+
Intent classes map color tokens into button tone slots. [Presentation](./composing.md#presentation) decides how much of that intent reaches background, text, border, and hover.
|
|
12
|
+
|
|
13
|
+
Intent classes:
|
|
14
|
+
|
|
15
|
+
| Class | Meaning |
|
|
16
|
+
| ----------------------------------- | ------------------------------ |
|
|
17
|
+
| `.neutral` _(default)_ | No specific intent. |
|
|
18
|
+
| `.primary` | Primary action. |
|
|
19
|
+
| `.secondary` | Secondary/accent action. |
|
|
20
|
+
| `.success` | Successful or positive action. |
|
|
21
|
+
| `.warning` | Warning/caution action. |
|
|
22
|
+
| `.destructive`, `.danger`, `.error` | Destructive or error action. |
|
|
23
|
+
| `.info` | Informational action. |
|
|
24
|
+
|
|
25
|
+
Every component that supports intent accepts the same list and reads the same [intent tokens](./theming.md#intent-tokens), so a custom intent class works everywhere without touching a component.
|
|
26
|
+
|
|
27
|
+
`.neutral` is the only intent that does not fill all the way. Its color is the page's own text color, so a full fill of it would be a black or white slab — the loudest element on the page, for the intent that means nothing in particular. It stops at `--intent-fill-max`, which is why a `.solid` neutral is a quiet plate a step past `.soft` rather than a block of ink. Set the slot on your own intent classes; see [Theming → Intent tokens](./theming.md#intent-tokens).
|
|
28
|
+
|
|
29
|
+
Size and shape classes:
|
|
30
|
+
|
|
31
|
+
| Class | Purpose |
|
|
32
|
+
| ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
33
|
+
| `.pill` | Fully rounded button corners (`border-radius: 9999px`). |
|
|
34
|
+
| `.sm` | Smaller button. |
|
|
35
|
+
| `.lg` | Larger button. |
|
|
36
|
+
| `.p-xs`, `.dense` | Tightest padding modifier (`px-2 py-0.5`; icon `p-0.5`). Also drops the `--control-height` minimum so a chip-sized button fits a table cell or a dense toolbar; every other size and padding class keeps that floor. An icon-only button at this tier gives up its `min-width` too, so size the glyph yourself. |
|
|
37
|
+
| `.p-sm`, `.compact` | Compact padding modifier (`px-2.5 py-1`; icon `p-1`). |
|
|
38
|
+
| `.p-lg`, `.spacious` | Spacious padding modifier (`px-6 py-3`; icon `p-3`). |
|
|
39
|
+
| `.icon` | Square icon button. Use an accessible name in HTML. |
|
|
40
|
+
| `.loading` | Loading state. Hides text and shows CSS activity indicator. |
|
|
41
|
+
| `.disabled`, `[disabled]`, `[aria-disabled="true"]`, `[data-disabled]` | Disabled styling. |
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
|
|
45
|
+
```html
|
|
46
|
+
<button class="btn primary">Primary</button>
|
|
47
|
+
<button class="btn success ghost edged">Success outline</button>
|
|
48
|
+
<button class="btn warning soft">Warning soft</button>
|
|
49
|
+
<button class="btn destructive ghost edgeless">Danger ghost</button>
|
|
50
|
+
<button class="btn icon primary" aria-label="Create">+</button>
|
|
51
|
+
<button class="btn primary loading" disabled>Saving</button>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`.loading` is a state, not a color or presentation class. Prefer combining it with disabled behavior so users cannot trigger duplicate work. Loading buttons keep only opacity and transform transitions active so spinner and surface colors stay synchronized when theme tokens change.
|
|
55
|
+
|
|
56
|
+
On the base look a press scales the button down a little (`--ui-active-transform`, `scale(0.97)`). [Aesthetics](./aesthetics.md) swap in their own press gesture, and `prefers-reduced-motion` turns it off.
|
|
57
|
+
|
|
58
|
+
Use `<button>` for actions or an accessible link for navigation; see [Accessibility](../accessibility.md).
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Composing
|
|
3
|
+
description: Combining intent, presentation, and aesthetic on a component, and the axis-support matrix.
|
|
4
|
+
order: 1
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Composing the three axes
|
|
8
|
+
|
|
9
|
+
See [Concepts](../concepts.md#the-three-axes) for what each axis means. This page covers how they combine in markup, what the presentation classes mean in depth, which components support which axis, and elevation.
|
|
10
|
+
|
|
11
|
+
## Combining axes
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<div class="soft">
|
|
15
|
+
<button class="btn primary">Soft primary button</button>
|
|
16
|
+
<span class="badge success">Soft success badge</span>
|
|
17
|
+
<button class="btn primary ghost edged">Outlined; the element wins</button>
|
|
18
|
+
</div>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
A declaration on the element always beats one inherited from a container, so a container sets the default look for its subtree and any element opts out.
|
|
22
|
+
|
|
23
|
+
Intent classes do not cascade. `.primary` and its siblings stay on the element that shows the intent, because a container silently recoloring every descendant is a trap rather than a feature — see [Theming → Intent tokens](./theming.md#intent-tokens). Use `.neutral` to opt an element back out of an inherited intent context. Presentation and [material tokens](./customizing.md#material-tokens) do cascade, so a container can set the look of its whole subtree while any element overrides it.
|
|
24
|
+
|
|
25
|
+
## Presentation
|
|
26
|
+
|
|
27
|
+
Presentation has two independent axes. `.solid`, `.soft`, and `.ghost` decide how much intent fills a component; `.edged` and `.edgeless` decide whether it draws a boundary. They set [presentation tokens](./customizing.md#presentation-tokens) and nothing else, so they work on the component itself or on any ancestor.
|
|
28
|
+
|
|
29
|
+
| Class | Look |
|
|
30
|
+
| ----------- | ---------------------------------------------------------- |
|
|
31
|
+
| `.solid` | Intent-colored fill with contrast text. |
|
|
32
|
+
| `.soft` | Lightly tinted fill with intent-colored text. |
|
|
33
|
+
| `.ghost` | No fill at rest, with intent-colored text. |
|
|
34
|
+
| `.edged` | Intent-colored boundary at the aesthetic's material width. |
|
|
35
|
+
| `.edgeless` | No boundary. |
|
|
36
|
+
|
|
37
|
+
Values each class ships:
|
|
38
|
+
|
|
39
|
+
| Class | `--ui-fill` | `--ui-fg-on-fill` | `--ui-border` |
|
|
40
|
+
| ----------- | ----------- | ----------------- | ------------- |
|
|
41
|
+
| `.solid` | `100%` | `100%` | |
|
|
42
|
+
| `.soft` | `12%` | `0%` | |
|
|
43
|
+
| `.ghost` | `0%` | `0%` | |
|
|
44
|
+
| `.edged` | | | `100%` |
|
|
45
|
+
| `.edgeless` | | | `0%` |
|
|
46
|
+
|
|
47
|
+
The combinations mean exactly what they spell:
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<button class="btn primary">Solid, the button default</button>
|
|
51
|
+
<button class="btn soft edged">Tinted with a border</button>
|
|
52
|
+
<button class="btn primary ghost edged">Outline</button>
|
|
53
|
+
<button class="btn ghost">Ghost; picks up a tint on hover</button>
|
|
54
|
+
<input class="ipt soft edgeless" />
|
|
55
|
+
<!-- A field sunk into the page -->
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
A fill class never decides an edge and an edge class never decides a fill. Use `.solid.edgeless` for a filled box with no line — and prefer it on a neutral one, because a capped fill leaves the box translucent and the edge blend then paints a second coat of the same tint rather than disappearing into it (measured 1.53:1 against its own plate in light, 1.82:1 in dark).
|
|
59
|
+
|
|
60
|
+
The edge is the silhouette and nothing else. Rules _inside_ a component that has an inside are a separate switch — see [Content and layout → Table rules](./content-and-layout.md#table-rules) — because tying them to this axis made them arrive by implication rather than by request.
|
|
61
|
+
|
|
62
|
+
With no presentation class in scope, each component keeps its own default: buttons are filled, alerts and badges are tinted, surfaces and controls are neutral and bordered.
|
|
63
|
+
|
|
64
|
+
| Component | Reads |
|
|
65
|
+
| ----------------------------------------------- | ------------------------------------------- |
|
|
66
|
+
| `.btn`, `.alert`, `.badge`, `.card`, `.panel` | Fill, text, border, and border width. |
|
|
67
|
+
| `.kbd` | Fill, text, border, and border width. |
|
|
68
|
+
| `.data-table` | Header fill and text, border, border width. |
|
|
69
|
+
| `.ipt`, `.textarea`, `.select`, `.text-control` | Border, border width, and a capped fill. |
|
|
70
|
+
| `.input-group` | Border, border width, and a capped fill. |
|
|
71
|
+
| `.checkbox`, `.radio` | A capped fill, checked and unchecked. |
|
|
72
|
+
| `.switch` | Border, border width, and a capped fill. |
|
|
73
|
+
| `.quote` | Fill, text, border, and width. |
|
|
74
|
+
| `.code`, `.pre`, `.tooltip` | Fill, text, border, and material. |
|
|
75
|
+
| `.loader`, `.skeleton`, `.progress`, `.divider` | Intent only, not presentation. |
|
|
76
|
+
|
|
77
|
+
Text controls and toggles cap a **cascaded** fill at `6%`, keeping typed text legible when a `.solid` container reaches a field nobody classed. A fill class written on the control itself names its own cap instead, because that is a consumer describing what they want: `.soft` takes `12%` and `.solid` takes `20%`. A switch caps at `40%`, where its three fills separate far enough to read on a track.
|
|
78
|
+
|
|
79
|
+
| On a text control | fill |
|
|
80
|
+
| ----------------- | ---- |
|
|
81
|
+
| `.ghost` | 0% |
|
|
82
|
+
| cascaded `.solid` | 6% |
|
|
83
|
+
| `.soft` | 12% |
|
|
84
|
+
| `.solid` | 20% |
|
|
85
|
+
|
|
86
|
+
The same split governs the edge: a cascaded `.edgeless` is floored and the element's own is honoured — except on `.checkbox` and `.radio`, which never drop their line at all. See [Forms](./forms.md) for the full toggle and text control reference.
|
|
87
|
+
|
|
88
|
+
A tooltip bubble is filled, over a tinted ground. An intent fills it with that intent's own color: `.tooltip.primary` is the primary color, black on a light page and white on a dark one, and `.tooltip.destructive` is a red bubble.
|
|
89
|
+
|
|
90
|
+
With no intent the bubble is `--color-tooltip`, the one plate in the package chosen per theme rather than derived from an intent. Composed like everything else it was `20%` of the page's ink over the surface tone, which steps _lighter_ than the surface on a dark page and _darker_ on a light one — so the dark bubble read as lifted and the light one as a mid-grey slab two steps darker than every card on the screen. The token states each direction instead: near-white over a light page, a mid grey over a dark one. `--color-tooltip-contrast` is its ink.
|
|
91
|
+
|
|
92
|
+
Near-white is only 1.04:1 against a light page, so the bubble draws a hairline as well, and floors it: a container's `.solid` or `.edgeless` cannot take the boundary away from a bubble nobody classed, while `.tooltip.edgeless` still can. The ground keeps the bubble opaque at every fill, so a cascaded presentation leaves it readable over whatever it floats above. It reads the material tokens too, so an [aesthetic](./aesthetics.md) in scope shapes the bubble like any other component. See [Tooltips](./tooltips.md) for the full tooltip reference.
|
|
93
|
+
|
|
94
|
+
## Component axis reference
|
|
95
|
+
|
|
96
|
+
This table is the authoritative axis map for demonstrated components. "Shape" means the component reads applicable radius, border-width, shadow, hover, or clip/edge material tokens; an aesthetic may intentionally affect only the materials that component draws.
|
|
97
|
+
|
|
98
|
+
Presentation is two independent axes, so they get a column each. A `Yes` means the class changes what the component computes, which `tests/browser/axes.spec.ts` asserts against `registry.json` in both directions: an axis marked `Yes` must move, and an axis marked `No` must not.
|
|
99
|
+
|
|
100
|
+
| Components | Intent | Fill | Edge | Aesthetic material |
|
|
101
|
+
| --------------------------------------------------------- | ------ | ---- | ---- | ------------------ |
|
|
102
|
+
| `.btn`, `.alert`, `.badge`, `.card`, `.panel` | Yes | Yes | Yes | Shape |
|
|
103
|
+
| `.loader` | Yes | No | No | No |
|
|
104
|
+
| `.kbd`, `.data-table` | Yes | Yes | Yes | Radius and edge |
|
|
105
|
+
| `.quote` | Yes | Yes | Yes | Edge width |
|
|
106
|
+
| `.divider`, `.skeleton` | Yes | No | No | No |
|
|
107
|
+
| `.ipt`, `.textarea`, `.select`, `.text-control` | Yes | Yes | Yes | Shape |
|
|
108
|
+
| `.input-group` | Yes | Yes | Yes | Shape |
|
|
109
|
+
| `.surface` | Yes | Yes | Yes | Shape |
|
|
110
|
+
| `.checkbox`, `.radio` | Yes | Yes | No | Radius and edge |
|
|
111
|
+
| `.switch` | Yes | Yes | Yes | Radius and edge |
|
|
112
|
+
| `.progress` | Yes | No | No | No |
|
|
113
|
+
| `.code`, `.pre` | Yes | Yes | Yes | Radius and clip |
|
|
114
|
+
| `.tooltip` | Yes | Yes | Yes | Shape and overlay |
|
|
115
|
+
| `.table-wrap`, `.quote-inline`, layout and text utilities | No | No | No | No |
|
|
116
|
+
|
|
117
|
+
`.checkbox` and `.radio` are the only components that read one axis and not the other. Their line is the only thing marking an unchecked box, so it is drawn whatever the edge class says, from a container or from the element itself. `.edgeless` on either is unsupported rather than merely discouraged.
|
|
118
|
+
|
|
119
|
+
Every other text control floors a _cascaded_ `.edgeless` and honours its own: a `.edgeless` toolbar will not erase the line of a field nobody classed, while `.ipt.edgeless` is a consumer describing what they want and gets it.
|
|
120
|
+
|
|
121
|
+
Intent aliases such as `.danger` and `.error` occupy the same intent axis as `.destructive`; they do not add component behavior. State and modifier classes such as `.interactive`, `.hoverable`, `.pressable`, `.loading`, `.invalid`, `.compact`, and `.vertical` sit above this map and are documented with their component.
|
|
122
|
+
|
|
123
|
+
## Elevation
|
|
124
|
+
|
|
125
|
+
Depth is a modifier, not an axis. Nothing is raised until an [aesthetic](./aesthetics.md) draws depth or one of these classes asks for it.
|
|
126
|
+
|
|
127
|
+
| Class | Alias | Depth |
|
|
128
|
+
| ----------------- | ----------- | ------------------------------------------------------------------------ |
|
|
129
|
+
| `.elevation-none` | `.flat` | Removes part-based elevation; glass surfaces keep their complete shadow. |
|
|
130
|
+
| `.elevation-sm` | `.raised` | One unit of the depth in scope. Cards, tiles, popovers that sit close. |
|
|
131
|
+
| `.elevation-md` | `.floating` | Twice it, for menus and popovers. |
|
|
132
|
+
|
|
133
|
+
Both names in a row are equivalent, interchangeable classes — `.elevation-sm` and `.raised` are aliases, not a canonical form and a deprecated one, the way `.destructive` and `.danger` are on the intent axis. The `none`/`sm`/`md` naming matches the raw `--elevation-*` tokens in [Theming](./theming.md#foundation-tokens) for the same weight of depth, even though the two are read from different places.
|
|
134
|
+
|
|
135
|
+
Each is one unitless multiplier over whatever shadow geometry is in scope, so the same class reads as a soft blur on a plain page and as a hard offset slab under `.neobrutalism` — the aesthetic decides what depth looks like, the class decides how much of it this element takes.
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<article class="card elevation-sm">Lifted</article>
|
|
139
|
+
<div class="elevation-md panel">A menu surface</div>
|
|
140
|
+
<article class="card elevation-none">Flat, whatever the page or container says</article>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The multiplier is a plain number, so it inherits: a container lifts or flattens a whole region and any element inside it still opts out on itself. Spread is deliberately left out of the multiplication, because an aesthetic that draws its edge as an inset ring spends spread on it and scaling that would erase the edge.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Content and layout
|
|
3
|
+
description: Layout helpers, content chips and tables, surfaces, and typography utilities.
|
|
4
|
+
order: 9
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Content and layout
|
|
8
|
+
|
|
9
|
+
## Layout
|
|
10
|
+
|
|
11
|
+
Layout helpers use the shared `--layout-gap` token. `.tight` sets it to `0.5rem` and `.loose` sets it to `1.5rem` within a view, stack, cluster, or auto-grid.
|
|
12
|
+
|
|
13
|
+
- `.view` is a flex container; `.vertical` and `.horizontal` set its direction, and horizontal views wrap with centered cross-axis alignment.
|
|
14
|
+
- `.stack` is a vertical flex stack.
|
|
15
|
+
- `.cluster` is a wrapping horizontal flex row; `.between` adds `space-between` alignment.
|
|
16
|
+
- `.auto-grid` is a responsive auto-fit grid using `--layout-grid-min`.
|
|
17
|
+
- `.tight` and `.loose` set the shared gap to `0.5rem` or `1.5rem` on views, stacks, clusters, and auto-grids.
|
|
18
|
+
- `.section` adds responsive block padding and an inline gutter.
|
|
19
|
+
- `.section-content` centers content at `--container-max`; `.narrow` and `.wide` select the corresponding container tokens.
|
|
20
|
+
- `.divider` is horizontal; `.vertical` makes it self-stretch vertically. It takes intent, but presentation classes do not affect it.
|
|
21
|
+
|
|
22
|
+
The removed `--layout-stack-gap` and `--layout-cluster-gap` tokens have no compatibility aliases.
|
|
23
|
+
|
|
24
|
+
## Content
|
|
25
|
+
|
|
26
|
+
| Class | Purpose | Intent affects |
|
|
27
|
+
| --------------- | ---------------------------------------------------------------------------------------- | ---------------------- |
|
|
28
|
+
| `.table-wrap` | Full-width horizontal overflow wrapper for wide tables. | Nothing. |
|
|
29
|
+
| `.data-table` | Rounded nested table styling for captions, heads, footers, cells, and rows. | Head, border, hover. |
|
|
30
|
+
| `.ruled` | On `.data-table`. Draws a rule between body rows. | Rule color. |
|
|
31
|
+
| `.ruleless` | On `.data-table`. Draws no lines inside the table at all. | Nothing. |
|
|
32
|
+
| `.kbd` | Inline keyboard-input styling. | Surface, border, text. |
|
|
33
|
+
| `.quote` | Block quote styling; a nested `cite` is set upright and takes the quotation's own color. | Bar, surface, text. |
|
|
34
|
+
| `.quote-inline` | Inline quotation styling. | Nothing. |
|
|
35
|
+
| `.code` | Inline code formatting. | Surface. |
|
|
36
|
+
| `.pre` | Scrollable block code formatting with larger padding. | Surface. |
|
|
37
|
+
|
|
38
|
+
### Table rules
|
|
39
|
+
|
|
40
|
+
A table draws three kinds of line, and `.ruled` and `.ruleless` move all of them together:
|
|
41
|
+
|
|
42
|
+
| Class | Head and foot boundaries | Rules between body rows |
|
|
43
|
+
| ----------- | ------------------------ | ----------------------- |
|
|
44
|
+
| `.ruleless` | No | No |
|
|
45
|
+
| _no class_ | Yes | No |
|
|
46
|
+
| `.ruled` | Yes | Yes |
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
<table class="data-table">
|
|
50
|
+
Head and foot boundaries only
|
|
51
|
+
</table>
|
|
52
|
+
<table class="data-table ruled">
|
|
53
|
+
Every row separated
|
|
54
|
+
</table>
|
|
55
|
+
<table class="data-table ruleless">
|
|
56
|
+
No lines inside the table at all
|
|
57
|
+
</table>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The boundaries under a head and above a foot separate the parts of a table from each other, so they are drawn by default where the row rules are not. Rules between body rows used to arrive on their own, because the component's published edge default is `edged` and the edge axis wrote the rules along with the boundary — so whether you got them depended on a registry default rather than on anything in your markup.
|
|
61
|
+
|
|
62
|
+
`--ui-rule` is the token behind both classes, so a container can set the answer for a whole region without classing each table:
|
|
63
|
+
|
|
64
|
+
```html
|
|
65
|
+
<section style="--ui-rule: 100%">
|
|
66
|
+
<table class="data-table">
|
|
67
|
+
Ruled by the region
|
|
68
|
+
</table>
|
|
69
|
+
</section>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The frame around the table is the edge axis and is asked for the same way: `.data-table` publishes `edgeless`, so `.edged` draws one. None of the three switches reaches the others — `.data-table.ruleless.edged` is a framed table with no lines inside it, and `.data-table.ruled` is a frameless one with every row separated.
|
|
73
|
+
|
|
74
|
+
A table's rows deliberately inherit its intent instead of resetting it, so `.data-table.success` tints throughout. A row carrying its own intent still wins:
|
|
75
|
+
|
|
76
|
+
```html
|
|
77
|
+
<table class="data-table success">
|
|
78
|
+
<tbody>
|
|
79
|
+
<tr>
|
|
80
|
+
<td>Inherits the table intent</td>
|
|
81
|
+
</tr>
|
|
82
|
+
<tr class="destructive">
|
|
83
|
+
<td>Overrides it for this row</td>
|
|
84
|
+
</tr>
|
|
85
|
+
</tbody>
|
|
86
|
+
</table>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
This is the one place intent cascades, because a table's rows are parts of the table rather than independent components.
|
|
90
|
+
|
|
91
|
+
`.data-table`, `.kbd`, `.code`, and `.pre` also read [presentation](./composing.md#presentation). A table applies it to its header, its rules and its border; a chip to its whole plate:
|
|
92
|
+
|
|
93
|
+
```html
|
|
94
|
+
<table class="data-table success soft edged">
|
|
95
|
+
...
|
|
96
|
+
</table>
|
|
97
|
+
<table class="data-table">
|
|
98
|
+
A ghost table: rules and type, no header plate
|
|
99
|
+
</table>
|
|
100
|
+
<kbd class="kbd primary solid">Ctrl</kbd>
|
|
101
|
+
<kbd class="kbd primary soft edged">Shift</kbd>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`.ghost` means two different things on these components, and both are worth knowing before you reach for it.
|
|
105
|
+
|
|
106
|
+
On `.data-table` it removes the header plate along with the body tint, so `.data-table.ghost` is boundaries and type alone. The component rests at `soft`, so that is something to ask for rather than the default.
|
|
107
|
+
|
|
108
|
+
On `.kbd`, `.code`, and `.pre` it is **not supported**. All three rest on `--intent-subtle`, and that ground draws the plate whatever the fill says — so `.ghost` took the fill away and changed nothing visible. Worse, the ground alone is a near-page tint: a ghost chip measured the same `#e5e5e5` for neutral and primary on the light page, and `#f5f5f5` at 1.04:1 against it for secondary. All three rest at `.soft` instead, which puts a real `12%` of the intent over the ground and separates them.
|
|
109
|
+
|
|
110
|
+
Use `.table-wrap` around `.data-table` when table width may exceed its container:
|
|
111
|
+
|
|
112
|
+
```html
|
|
113
|
+
<div class="table-wrap">
|
|
114
|
+
<table class="data-table">
|
|
115
|
+
<thead>
|
|
116
|
+
<tr>
|
|
117
|
+
<th>Package</th>
|
|
118
|
+
<th>Status</th>
|
|
119
|
+
</tr>
|
|
120
|
+
</thead>
|
|
121
|
+
<tbody>
|
|
122
|
+
<tr>
|
|
123
|
+
<td>styles</td>
|
|
124
|
+
<td>Ready</td>
|
|
125
|
+
</tr>
|
|
126
|
+
</tbody>
|
|
127
|
+
</table>
|
|
128
|
+
</div>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Surfaces
|
|
132
|
+
|
|
133
|
+
| Class | Purpose |
|
|
134
|
+
| -------------------- | ------------------------------------------------------------------------------------- |
|
|
135
|
+
| `.card` | Bordered container, surface radius, padded. Rests at elevation `1`. |
|
|
136
|
+
| `.panel` | Flush container for sidebars, toolbars, and wells. No elevation. |
|
|
137
|
+
| `.interactive` | On `.card`. Adds pointer cursor, hover and press response, and a focus ring. |
|
|
138
|
+
| `.hoverable` | On `.card`. The hover half of `.interactive`: hover response only, no pointer cursor. |
|
|
139
|
+
| `.pressable` | On `.card`. The press half of `.interactive`: press response and pointer cursor. |
|
|
140
|
+
| `.p-xs`, `.dense` | On `.card` or `.panel`. Reduces padding further than `.compact`. |
|
|
141
|
+
| `.p-sm`, `.compact` | On `.card` or `.panel`. Reduces padding. |
|
|
142
|
+
| `.p-lg`, `.spacious` | On `.card` or `.panel`. Increases padding. |
|
|
143
|
+
| `.flush` | On `.card` or `.panel`. Removes padding, for edge-to-edge content. |
|
|
144
|
+
|
|
145
|
+
Both read intent, [presentation](./composing.md#presentation), and [material tokens](./customizing.md#material-tokens). A plain `.card` is a neutral bordered container; only an explicit presentation tints it. Resting at elevation `1` is not a visible shadow by itself — nothing draws depth until an [aesthetic](./aesthetics.md) supplies shadow geometry or `.elevation-sm`/`.elevation-md` asks for it; see [Composing → Elevation](./composing.md#elevation).
|
|
146
|
+
|
|
147
|
+
On the base look, `.card.interactive` scales down slightly on press (`--ui-active-transform`, `scale(0.97)`); an [aesthetic](./aesthetics.md) substitutes its own press gesture, and `prefers-reduced-motion` turns it off.
|
|
148
|
+
|
|
149
|
+
`.interactive` is the pair `.hoverable` (hover response only, no pointer cursor) and `.pressable` (press response and pointer cursor) applied together. Take one half for a card that answers a single gesture: a card that warms on hover but holds its own action in a nested button takes `.hoverable`, so pressing that button does not dip the whole card.
|
|
150
|
+
|
|
151
|
+
```html
|
|
152
|
+
<article class="card">Neutral card</article>
|
|
153
|
+
<article class="card success soft">Tinted success card</article>
|
|
154
|
+
<article class="card primary ghost edged">Intent border, no fill</article>
|
|
155
|
+
<a class="card interactive" href="/package">Responds to hover and press</a>
|
|
156
|
+
<article class="card hoverable">Warms on hover; the action is a nested button</article>
|
|
157
|
+
<aside class="panel">Flush panel</aside>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`.interactive` and `.pressable` are styling only. Use a real interactive element and give it an accessible name; a `<div class="card interactive">` is not focusable or operable by keyboard.
|
|
161
|
+
|
|
162
|
+
## Typography utilities
|
|
163
|
+
|
|
164
|
+
All typography classes and `.selection-contrast` are `@utility` classes.
|
|
165
|
+
|
|
166
|
+
| Class | Purpose |
|
|
167
|
+
| --------------------- | ------------------------------------------------------------ |
|
|
168
|
+
| `.text-display` | Large display headings. |
|
|
169
|
+
| `.text-title-lg` | Large section titles. |
|
|
170
|
+
| `.text-title` | Default section titles. |
|
|
171
|
+
| `.text-title-sm` | Smaller titles or card titles. |
|
|
172
|
+
| `.text-label-lg` | Large label text. |
|
|
173
|
+
| `.text-label` | Default label text. |
|
|
174
|
+
| `.text-body` | Default body copy. |
|
|
175
|
+
| `.selection-contrast` | Inverts `::selection` colors to primary-contrast background. |
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Customizing
|
|
3
|
+
description: Presentation and material token reference, and aesthetic knobs.
|
|
4
|
+
order: 3
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Customizing
|
|
8
|
+
|
|
9
|
+
Presentation tokens decide how much of an intent shows. Material tokens decide what a component is made of. Aesthetic tokens are the small set of named knobs a shipped aesthetic exposes to scale its own look.
|
|
10
|
+
|
|
11
|
+
## Presentation tokens
|
|
12
|
+
|
|
13
|
+
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
|
+
|
|
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 readable tone toward its contrast tone. |
|
|
19
|
+
| `--ui-border` | Percentage of the intent color mixed into the border color. |
|
|
20
|
+
|
|
21
|
+
A component resolves them with `color-mix` from its published default. Hover is derived by adding `--hover-step` to the resting fill and using `--intent-hover`; there are no per-presentation hover tokens.
|
|
22
|
+
|
|
23
|
+
No fill class writes `--ui-border` and no edge class writes `--ui-fill`. A filled box with no line is `.solid.edgeless`, which is worth reaching for on a neutral component: neutral caps its fill, so the box stays translucent and a border over it paints a second coat of the same tint instead of blending into it.
|
|
24
|
+
|
|
25
|
+
```css
|
|
26
|
+
background: color-mix(in oklab, var(--color-primary) var(--ui-fill, 100%), transparent);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Two choices there are deliberate. Mixing toward `transparent` rather than a background token lets a tinted surface adapt to whatever it is placed on. Mixing in `oklab` keeps the wide-gamut token palette intact and blends perceptually, where `srgb` would clip it.
|
|
30
|
+
|
|
31
|
+
A computed color therefore reaches the page as a resolved `color-mix` result rather than the token's own `oklch` syntax. It is the same color; code that compares computed color strings should compare colors instead.
|
|
32
|
+
|
|
33
|
+
> **Presentation token contract**: only presentation classes and consumer overrides set these tokens; components only read them. Setting a value that no presentation class produces is supported but unvalidated. See [Composing](./composing.md) for the classes that ship these values.
|
|
34
|
+
|
|
35
|
+
## Material tokens
|
|
36
|
+
|
|
37
|
+
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
|
+
|
|
39
|
+
Components read each with a fallback, so leaving them unset produces the default look. Setting them on a container restyles the whole subtree. Only shadow geometry is split into colorless parts that inherit safely; color-capable inputs such as `--ui-ink` and `--ui-surface-shadow` may include their own colors.
|
|
40
|
+
|
|
41
|
+
| Token | Purpose | Fallback |
|
|
42
|
+
| ----------------------- | ------------------------------------------------------------------------------------------------------------- | -------------------- |
|
|
43
|
+
| `--ui-radius` | Corner radius for controls. | `--radius-control` |
|
|
44
|
+
| `--ui-radius-surface` | Corner radius for surfaces. | `--radius-surface` |
|
|
45
|
+
| `--ui-border-width` | Edge thickness. | `--border-width` |
|
|
46
|
+
| `--ui-border-max` | Ceiling on computed edge width. | `100px` |
|
|
47
|
+
| `--ui-ink` | Neutral line color when no intent is set. | `--color-border` |
|
|
48
|
+
| `--ui-rule` | Lines inside a table. Unset draws the head and foot boundaries only; `0%` draws none; `100%` rules every row. | unset |
|
|
49
|
+
| `--ui-shadow-x` | Shadow horizontal offset. | `0px` |
|
|
50
|
+
| `--ui-shadow-y` | Shadow vertical offset. | `0px` |
|
|
51
|
+
| `--ui-shadow-blur` | Shadow blur radius. | `0px` |
|
|
52
|
+
| `--ui-shadow-spread` | Shadow spread radius. | `0px` |
|
|
53
|
+
| `--ui-shadow-inset` | The `inset` keyword for an inner ring. | Empty |
|
|
54
|
+
| `--ui-hover-shadow-x` | Shadow horizontal offset while hovered. | `--ui-shadow-x` |
|
|
55
|
+
| `--ui-hover-shadow-y` | Shadow vertical offset while hovered. | `--ui-shadow-y` |
|
|
56
|
+
| `--ui-active-shadow-x` | Shadow horizontal offset while pressed. | `--ui-shadow-x` |
|
|
57
|
+
| `--ui-active-shadow-y` | Shadow vertical offset while pressed. | `--ui-shadow-y` |
|
|
58
|
+
| `--ui-active-transform` | Transform while pressed. `none` under `prefers-reduced-motion`. | `scale(0.97)` |
|
|
59
|
+
| `--ui-shadow-ink` | Percentage of shadow color taken from intent ink. | `0%` |
|
|
60
|
+
| `--ui-shadow-edge` | Declared, even empty, when the shadow is the element's edge rather than its depth. Read for presence. | Unset |
|
|
61
|
+
| `--ui-elevation` | Unitless multiplier over shadow geometry. | `1` |
|
|
62
|
+
| `--ui-surface-shadow` | Complete multi-layer shadow accepted by surfaces only. | Unset |
|
|
63
|
+
| `--ui-surface-ground` | Ground a surface sits on. | `--color-background` |
|
|
64
|
+
| `--ui-bg-alpha` | Multiplier over fill for translucent materials. | `1` |
|
|
65
|
+
| `--ui-backdrop` | Backdrop filter accepted by surfaces only. | `none` |
|
|
66
|
+
| `--ui-hover-transform` | Transform while an interactive element is hovered. | `none` |
|
|
67
|
+
| `--ui-clip` | Structural component silhouette. | `none` |
|
|
68
|
+
| `--ui-clip-tight` | Compact component silhouette. | `--ui-clip` |
|
|
69
|
+
| `--ui-focus-inset` | Inset focus layer width. | Unset |
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<section style="--ui-radius: 0; --ui-border-width: 3px">
|
|
73
|
+
<button class="btn primary">Square and heavy</button>
|
|
74
|
+
<input class="ipt" placeholder="Matches" />
|
|
75
|
+
</section>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
> **Material token contract**: components read these; aesthetic classes and consumer overrides set them.
|
|
79
|
+
|
|
80
|
+
### Shape and ring composition
|
|
81
|
+
|
|
82
|
+
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`.
|
|
83
|
+
|
|
84
|
+
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.
|
|
85
|
+
|
|
86
|
+
The token is read for its presence, not its value: declare it empty to switch the ring on, and `initial` to switch it back off in an aesthetic nested inside one that declares it.
|
|
87
|
+
|
|
88
|
+
```css
|
|
89
|
+
.stepped {
|
|
90
|
+
--ui-clip: polygon(/* structural silhouette */);
|
|
91
|
+
--ui-clip-tight: none;
|
|
92
|
+
--ui-border-max: 0px;
|
|
93
|
+
--ui-shadow-inset: inset;
|
|
94
|
+
--ui-shadow-edge: ;
|
|
95
|
+
--ui-shadow-x: 0px;
|
|
96
|
+
--ui-shadow-y: 0px;
|
|
97
|
+
--ui-shadow-blur: 0px;
|
|
98
|
+
--ui-shadow-spread: 4px;
|
|
99
|
+
--ui-focus-inset: var(--focus-ring-width);
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Variables prefixed `--_` are internal composition outputs — `--_bg`, `--_fg`, `--_edge`, `--_fill`, `--_shadow`, and the `--_d-*` resting slots a component states for `box` to read. Do not set or read them; only the `--ui-*` inputs above are public.
|
|
104
|
+
|
|
105
|
+
## Aesthetic tokens
|
|
106
|
+
|
|
107
|
+
The shipped [aesthetic classes](./aesthetics.md) set material tokens for you. Only aesthetics with a token listed below expose an aesthetic-specific token. Tune all other behavior through the shared material tokens above. Listed tokens are available only where that aesthetic's stylesheet is imported.
|
|
108
|
+
|
|
109
|
+
| Token | Aesthetic | Purpose | Default |
|
|
110
|
+
| ------------------------ | --------------- | ----------------------------------------------------------- | --------------------------------- |
|
|
111
|
+
| `--neo-offset` | `.neobrutalism` | Hard shadow offset and distance the press travels. | `4px` |
|
|
112
|
+
| `--glass-radius` | `.glass` | Control corner radius. | `0.75rem` |
|
|
113
|
+
| `--glass-radius-surface` | `.glass` | Surface corner radius. | `1rem` |
|
|
114
|
+
| `--pixel-unit` | `.pixel` | One pixel of the grid. The corner cut and the ring are one. | `4px` |
|
|
115
|
+
| `--font-pixel` | `.pixel` | Consumer-supplied pixel font stack. | Falls back to the monospace stack |
|
|
116
|
+
| `--tile-radius` | `.chunky-tile` | Corner radius, on controls and surfaces alike. | `0.75rem` |
|
|
117
|
+
| `--tile-lift` | `.chunky-tile` | Depth of the seated bar, and how far a press travels. | `4px` |
|
|
118
|
+
| `--font-rounded` | `.chunky-tile` | Consumer-supplied rounded font stack. | Falls back to the page stack |
|
|
119
|
+
|
|
120
|
+
All four aesthetics 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`:
|
|
121
|
+
|
|
122
|
+
```html
|
|
123
|
+
<section class="pixel" style="--pixel-unit: 6px">
|
|
124
|
+
<button class="btn primary">Chunkier</button>
|
|
125
|
+
</section>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```html
|
|
129
|
+
<html class="pixel" style="--pixel-unit: 6px">
|
|
130
|
+
<body>
|
|
131
|
+
<button class="btn primary">Also chunkier, set from the root</button>
|
|
132
|
+
</body>
|
|
133
|
+
</html>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Knobs and material tokens reach in opposite directions, and telling them apart matters. A knob resolves once at the aesthetic's own class and inherits down already-resolved, so it reaches the aesthetic **from above**: setting it on the element or any ancestor works, but setting it on a _descendant_ of the aesthetic class changes nothing — the value has already been read. `--ui-radius` and the other material tokens above are read fresh by each component as it draws, so they reach **at or below** the element carrying them, which is how you round one card differently from its neighbours without touching the knob at all.
|
|
137
|
+
|
|
138
|
+
Shipped aesthetics set the shared material tokens above. `.neobrutalism` and `.pixel` set `--ui-ink` for their neutral outline; intent classes still override the intent slots on each component.
|
|
139
|
+
|
|
140
|
+
## Component internals
|
|
141
|
+
|
|
142
|
+
Component classes may define scoped implementation variables such as `--surface-padding`, `--field-gap`, `--input-group-pad`, `--switch-*`, `--table-*`, `--quote-*`, and `--tooltip-*`. These variables are internal wiring for class composition and are not the public token contract.
|
|
143
|
+
|
|
144
|
+
Consumers should customize broad behavior through color, foundation, motion, elevation, radius, layout, and focus tokens first. The only supported component-scoped input is `--progress-value` on the `.progress` element, because consumers must provide a value such as `64%`.
|
|
145
|
+
|
|
146
|
+
`--layout-gap` replaces the removed `--layout-stack-gap` and `--layout-cluster-gap` tokens. No compatibility aliases are provided.
|
|
147
|
+
|
|
148
|
+
Next: [Aesthetics](./aesthetics.md) covers each shipped aesthetic's complete look and its documented exceptions.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Feedback
|
|
3
|
+
description: Alert, badge, loader, skeleton, and progress class reference.
|
|
4
|
+
order: 7
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Feedback
|
|
8
|
+
|
|
9
|
+
| Class | Purpose |
|
|
10
|
+
| ---------------- | ---------------------------------------------------------------------------- |
|
|
11
|
+
| `.alert` | Inline feedback surface. |
|
|
12
|
+
| `.icon` | Subclass of `.alert`. Adds a corresponding intent icon and padding. |
|
|
13
|
+
| `.badge` | Compact status pill. |
|
|
14
|
+
| `.loader-mask` | Low-level activity indicator composition utility. Applies the spinner mask. |
|
|
15
|
+
| `.loader` | Standalone inline loader artwork. |
|
|
16
|
+
| `.skeleton` | Ambient loading placeholder. |
|
|
17
|
+
| `.progress` | Progress track. Uses `--progress-value` variable. |
|
|
18
|
+
| `.active` | Optional on `.progress` to add a track shimmer. |
|
|
19
|
+
| `.indeterminate` | Optional on `.progress` to animate a moving fill without `--progress-value`. |
|
|
20
|
+
|
|
21
|
+
Activity indicator modifier classes compose with `.loader`:
|
|
22
|
+
|
|
23
|
+
| Class | Animation style |
|
|
24
|
+
| ---------------------- | --------------------------------------- |
|
|
25
|
+
| _(default)_ | Circular spinner (rotating arc). |
|
|
26
|
+
| `.dots-wave` | Three dots bouncing up/down in a wave. |
|
|
27
|
+
| `.dots-fade` | Three dots fading in and out. |
|
|
28
|
+
| `.dots-queue` | Dot queuing from left to right. |
|
|
29
|
+
| `.dots-rotate` | Side dots rotating around a center dot. |
|
|
30
|
+
| `.dots-grow` | Three dots growing and shrinking. |
|
|
31
|
+
| `.dots-grow-alternate` | Outer dots small, center dot pulses. |
|
|
32
|
+
| `.dot-bounce` | Single dot bouncing with squash effect. |
|
|
33
|
+
| `.bars-wave` | Three vertical bars scaling in a wave. |
|
|
34
|
+
| `.pulse-ring` | Two concentric rings pulsing outward. |
|
|
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 (`2rem`). |
|
|
43
|
+
| `.sm` | Small (`1.5rem`). |
|
|
44
|
+
| `.lg` | Large (`2.5rem`). |
|
|
45
|
+
|
|
46
|
+
Alerts, badges, progress bars, skeletons, and loaders accept `.primary`, `.secondary`, `.success`, `.warning`, `.destructive`, `.danger`, `.error`, 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, progress bars, and dividers are indicators. They read intent but ignore fill and edge [presentation](./composing.md#presentation).
|
|
49
|
+
|
|
50
|
+
```html
|
|
51
|
+
<span class="loader success" aria-hidden="true"></span> <span class="skeleton info"></span>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`.icon` is a subclass of `.alert`. When applied as `.alert.icon`, it increases the left padding and adds an embedded SVG. Success, warning, and destructive intents use corresponding symbols; other intents use the information symbol.
|
|
55
|
+
|
|
56
|
+
Alerts and badges read the shared [presentation](./composing.md#presentation) classes. Without one they use a tinted surface, intent-colored text, and a mixed intent border.
|
|
57
|
+
|
|
58
|
+
## Example
|
|
59
|
+
|
|
60
|
+
```html
|
|
61
|
+
<div class="alert success" role="status">Saved successfully.</div>
|
|
62
|
+
<div class="alert primary solid" role="status">Deployment started.</div>
|
|
63
|
+
<div class="alert warning soft icon" role="status">Review required.</div>
|
|
64
|
+
<div class="alert destructive ghost edged" role="alert">Deployment failed.</div>
|
|
65
|
+
<span class="badge warning">Queued</span>
|
|
66
|
+
<span class="badge success solid">Live</span>
|
|
67
|
+
<span class="badge info soft">Draft</span>
|
|
68
|
+
<span class="loader" aria-hidden="true"></span>
|
|
69
|
+
<span class="loader dots-wave" aria-hidden="true"></span>
|
|
70
|
+
<span class="loader dots-fade" aria-hidden="true"></span>
|
|
71
|
+
<span class="loader bars-wave" aria-hidden="true"></span>
|
|
72
|
+
<span class="loader pulse-ring sm" aria-hidden="true"></span>
|
|
73
|
+
<span class="loader dots-grow lg" aria-hidden="true"></span>
|
|
74
|
+
<div class="progress" role="progressbar" aria-label="Upload progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="64" style="--progress-value: 64%"></div>
|
|
75
|
+
<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>
|
|
76
|
+
<div class="progress info indeterminate" role="progressbar" aria-label="Loading" aria-valuemin="0" aria-valuemax="100"></div>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Add `role="status"` or `role="alert"` to alerts based on announcement urgency, mark decorative loading visuals with `aria-hidden="true"`, and use semantic progress elements or ARIA values when numeric progress must be announced; see [Accessibility](../accessibility.md).
|