@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
package/docs/usage/theming.md
CHANGED
|
@@ -1,154 +1,295 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Theming
|
|
3
|
-
description:
|
|
4
|
-
order:
|
|
3
|
+
description: Light and dark mode, replacing the palette with brand colors, defining an intent of your own, and every color, intent, foundation, and font token with its default.
|
|
4
|
+
order: 5
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Theming
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The settings screen works and looks like the package's defaults: near-black actions on a near-white page. This page makes it yours. It covers light and dark mode, then replaces the primary color with a brand color in both modes, then defines an intent the package does not ship. The second half is the lookup reference: every color, intent, foundation, and font token, with its default.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Light and dark
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Out of the box, the page follows the operating system: light when the user's system is light, dark when it is dark. You do nothing for that.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
To let the user choose, put a theme selector on the root element:
|
|
16
16
|
|
|
17
17
|
```html
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
</
|
|
18
|
+
<html data-theme="dark">
|
|
19
|
+
…
|
|
20
|
+
</html>
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
27
|
-
| `--color-primary-hover` | Primary hover state. |
|
|
28
|
-
| `--color-primary-subtle` | Low-emphasis companion tone for primary. Use as soft surface or subtle background. |
|
|
29
|
-
| `--color-primary-strong` | High-emphasis companion tone for primary. Use as readable text, icon, or border on subtle surfaces. |
|
|
30
|
-
| `--color-accent` | Secondary/accent surface. |
|
|
31
|
-
| `--color-accent-contrast` | Text/icon color on accent filled surface. |
|
|
32
|
-
| `--color-accent-hover` | Accent hover state. |
|
|
33
|
-
| `--color-accent-subtle` | Low-emphasis companion tone for accent. Use as soft surface or subtle background. |
|
|
34
|
-
| `--color-accent-strong` | High-emphasis companion tone for accent. Use as readable text, icon, or border on subtle surfaces. |
|
|
35
|
-
| `--color-border` | Default border color. |
|
|
36
|
-
| `--color-border-hover` | Interactive border color. |
|
|
37
|
-
| `--color-control-border` | Resting line on the six text controls; one value, drawn at a fraction on text inputs. |
|
|
38
|
-
| `--color-background` | Page and default raised surface background. |
|
|
39
|
-
| `--color-foreground` | Subtle raised foreground surface. |
|
|
40
|
-
| `--color-surface` | Nested or muted surface. |
|
|
41
|
-
| `--color-text` | Primary text color. |
|
|
42
|
-
| `--color-text-secondary` | Secondary text color. |
|
|
43
|
-
| `--color-text-contrast` | Readable color on top of a full fill of `--color-text`. A checked toggle prints it. |
|
|
44
|
-
| `--color-text-hover` | Text hover state. |
|
|
45
|
-
| `--color-text-strong` | High-emphasis companion tone for text. Use as readable text, icon, or border on subtle surfaces. |
|
|
46
|
-
| `--color-tooltip` | Tooltip bubble plate with no intent. Chosen per theme rather than derived: near-white in light, mid grey in dark. |
|
|
47
|
-
| `--color-tooltip-contrast` | Ink on `--color-tooltip`. |
|
|
48
|
-
| `--color-success` | Success state color. |
|
|
49
|
-
| `--color-success-contrast` | Text/icon color on success filled surface. Meets 4.5:1 as normal text on `--color-success` (5.14:1). |
|
|
50
|
-
| `--color-success-hover` | Success hover tone. |
|
|
51
|
-
| `--color-success-subtle` | Low-emphasis companion tone for success. |
|
|
52
|
-
| `--color-success-strong` | High-emphasis companion tone for success. |
|
|
53
|
-
| `--color-warning` | Warning state color. |
|
|
54
|
-
| `--color-warning-contrast` | The near-black tone, not the page tone. Meets 4.5:1 as normal text on `--color-warning` (6.19:1). |
|
|
55
|
-
| `--color-warning-hover` | Warning hover tone. |
|
|
56
|
-
| `--color-warning-subtle` | Low-emphasis companion tone for warning. |
|
|
57
|
-
| `--color-warning-strong` | High-emphasis companion tone for warning. |
|
|
58
|
-
| `--color-destructive` | Destructive/error state color. |
|
|
59
|
-
| `--color-destructive-contrast` | Text/icon color on destructive filled surface. Meets 4.5:1 as normal text on `--color-destructive` (5.78:1). |
|
|
60
|
-
| `--color-destructive-hover` | Destructive hover tone. |
|
|
61
|
-
| `--color-destructive-subtle` | Low-emphasis companion tone for destructive. |
|
|
62
|
-
| `--color-destructive-strong` | High-emphasis companion tone for destructive. |
|
|
63
|
-
| `--color-info` | Informational state color. |
|
|
64
|
-
| `--color-info-contrast` | Text/icon color on info filled surface. Meets 4.5:1 as normal text on `--color-info` (6.19:1). |
|
|
65
|
-
| `--color-info-hover` | Info hover tone. |
|
|
66
|
-
| `--color-info-subtle` | Low-emphasis companion tone for info. |
|
|
67
|
-
| `--color-info-strong` | High-emphasis companion tone for info. |
|
|
68
|
-
|
|
69
|
-
> **Intent token contract**: color intent tokens own meaning and tone variants. Intent classes map one family onto the shared intent slots below, and presentation classes decide how much of it a component shows. Theme changes belong in token values, not broad component-level theme checks. Component-level theme handling should exist only when a component has an internal structure that cannot be expressed through the token palette alone.
|
|
23
|
+
| Theme | Equivalent selectors |
|
|
24
|
+
| ----- | ------------------------------------------------ |
|
|
25
|
+
| Light | `.light`, `.theme-light`, `[data-theme="light"]` |
|
|
26
|
+
| Dark | `.dark`, `.theme-dark`, `[data-theme="dark"]` |
|
|
70
27
|
|
|
71
|
-
|
|
28
|
+
A settings screen with a "System / Light / Dark" choice removes the attribute for System and sets it for the other two.
|
|
29
|
+
|
|
30
|
+
How it resolves:
|
|
31
|
+
|
|
32
|
+
- A theme selector sets the CSS `color-scheme` property and nothing else. Every color token holds its light and its dark value at once, through `light-dark()`, and the element's `color-scheme` picks one.
|
|
33
|
+
- `color-scheme` inherits, so a selector themes everything inside it. A selector on any element themes that part of the page: a dark sidebar on a light page is `<aside class="dark">`.
|
|
34
|
+
- The nearest selector wins, at any depth. A `.light` card inside a `.dark` page is light.
|
|
35
|
+
- With no selector, the root has `color-scheme: light dark`, which follows the system.
|
|
36
|
+
- Put one theme on an element. If an element carries both a light and a dark selector, dark wins, but do not rely on that.
|
|
37
|
+
- Setting `color-scheme` yourself on an element works the same way, because it is the only thing the palette reads. It also themes native parts such as scrollbars and the inside of form controls.
|
|
38
|
+
|
|
39
|
+
Every component color comes from a token or from `currentColor`, so components follow the theme with no dark-mode rules of their own. The marks the package draws, such as the checkbox tick and the select arrow, use `currentColor` too. Icons and images you add are yours to theme.
|
|
40
|
+
|
|
41
|
+
`light-dark()` works from Chrome 123, Safari 17.5, and Firefox 120. The package as a whole needs Firefox 128; see [Setup → Requirements](../setup.md#requirements).
|
|
42
|
+
|
|
43
|
+
### The `dark:` variant
|
|
44
|
+
|
|
45
|
+
With the Tailwind source entrypoints (`/tw`), the package replaces Tailwind's `dark:` variant so your own utilities follow the same theme as the tokens. A `dark:` utility applies under an explicit dark selector on the element or an ancestor, or under a dark system preference when no ancestor sets a theme:
|
|
72
46
|
|
|
73
|
-
|
|
47
|
+
```html
|
|
48
|
+
<html>
|
|
49
|
+
<body>
|
|
50
|
+
<p class="dark:text-white">Follows the system preference</p>
|
|
51
|
+
<div class="light">
|
|
52
|
+
<p class="dark:text-white">Stays light: this part of the page chose a theme</p>
|
|
53
|
+
</div>
|
|
54
|
+
</body>
|
|
55
|
+
</html>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
It differs from the tokens in one case: an explicit theme nested inside the opposite one. A `.light` element inside a `.dark` one has light tokens, because the nearest `color-scheme` wins. But `dark:` matches by selector, and `.dark *` matches every element inside `.dark`, so a `dark:` utility inside that `.light` element still applies. If a page uses both tokens and `dark:` utilities, do not nest opposite themes.
|
|
59
|
+
|
|
60
|
+
The compiled entrypoints do not define a `dark:` variant; they have no Tailwind build to define it in.
|
|
61
|
+
|
|
62
|
+
## Change the brand color
|
|
63
|
+
|
|
64
|
+
The primary color is near-black on a light page and near-white on a dark one. To make it a brand color, replace the whole primary family: the base color and its four companions. Each holds a light and a dark value:
|
|
65
|
+
|
|
66
|
+
```css
|
|
67
|
+
:root {
|
|
68
|
+
--color-primary: light-dark(#0f766e, #2dd4bf);
|
|
69
|
+
--color-primary-contrast: light-dark(#ffffff, #042f2e);
|
|
70
|
+
--color-primary-hover: light-dark(#115e59, #5eead4);
|
|
71
|
+
--color-primary-subtle: light-dark(#ccfbf1, #134e4a);
|
|
72
|
+
--color-primary-strong: light-dark(#115e59, #5eead4);
|
|
73
|
+
}
|
|
74
|
+
```
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
| ------------------- | ------------------------------------------------------------------------------------- |
|
|
77
|
-
| `--intent-color` | The intent's base color. What a fill is made of. |
|
|
78
|
-
| `--intent-contrast` | Readable color on top of a filled `--intent-color`. |
|
|
79
|
-
| `--intent-hover` | The intent's hovered base color. |
|
|
80
|
-
| `--intent-strong` | The intent printed on a page. Text, icon, or border wherever the fill is not full. |
|
|
81
|
-
| `--intent-subtle` | Low-emphasis tone. Tinted surfaces and tracks. Neutral resolves to `--color-surface`. |
|
|
82
|
-
| `--intent-border` | Line color. Resolves to `--color-border` when no intent is set. |
|
|
83
|
-
| `--intent-fill-max` | How far a fill of this intent is allowed to go. `100%` for every intent but neutral. |
|
|
76
|
+
What each one is for:
|
|
84
77
|
|
|
85
|
-
|
|
78
|
+
| Token | Role | Check |
|
|
79
|
+
| -------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------- |
|
|
80
|
+
| `--color-primary` | The fill of a solid primary button, a checked toggle, a progress fill. | Text in `-contrast` on it reaches 4.5:1. |
|
|
81
|
+
| `--color-primary-contrast` | Text and icons on a full primary fill. | See above. |
|
|
82
|
+
| `--color-primary-hover` | The fill under the pointer. | Text in `-contrast` on it still reaches 4.5:1. |
|
|
83
|
+
| `--color-primary-subtle` | The light tint behind soft components. | Text in `-strong` on it reaches 4.5:1. |
|
|
84
|
+
| `--color-primary-strong` | Text, icons, and borders where the fill is not full: soft and ghost. | Reaches 4.5:1 on the page and on `-subtle`. |
|
|
86
85
|
|
|
87
|
-
The
|
|
86
|
+
The teal values above measure, in light and dark mode: 5.47:1 and 7.77:1 for the fill and its text, 7.27:1 and 13.38:1 for the strong tone on the page, and 6.73:1 and 6.41:1 for the strong tone on the subtle tint.
|
|
88
87
|
|
|
89
|
-
`--
|
|
88
|
+
Replace the whole family. Changing only `--color-primary` leaves its companions on the old near-black, so a soft primary badge keeps gray text and a hovered button flashes black. The focus ring is drawn from `--color-primary` at 64% opacity, so it follows the brand color without a change of its own.
|
|
90
89
|
|
|
91
|
-
|
|
90
|
+
The same pattern works for every family in [Color tokens](#color-tokens): `--color-accent` is what `.secondary` reads, and the four status families are `success`, `warning`, `destructive`, and `info`. Set them on `:root` for the whole page, or on any element to retheme only what is inside it.
|
|
92
91
|
|
|
93
|
-
The
|
|
92
|
+
The values must be complete colors: hex, `rgb()`, `oklch()`, or a variable you declared yourself. Tailwind palette variables such as `--color-teal-700` exist in a `/tw` build, from your Tailwind theme, but the compiled CSS declares only the palette colors the package itself uses. With compiled CSS, a reference to any other palette variable is empty, and the color it feeds is lost.
|
|
94
93
|
|
|
95
|
-
|
|
94
|
+
## Your own intent
|
|
96
95
|
|
|
97
|
-
|
|
96
|
+
The package ships six intents: `.primary`, `.secondary`, `.success`, `.warning`, `.destructive`, and `.info`, and the default, `.neutral`. To add one, such as a "Beta" color for features in preview, write a class that sets the seven intent slots. Use complete colors, with `light-dark()` for anything that changes between themes:
|
|
98
97
|
|
|
99
98
|
```css
|
|
100
|
-
.
|
|
101
|
-
--intent-color:
|
|
102
|
-
--intent-contrast:
|
|
103
|
-
--intent-hover:
|
|
104
|
-
--intent-strong:
|
|
105
|
-
--intent-subtle:
|
|
106
|
-
--intent-border:
|
|
99
|
+
.beta {
|
|
100
|
+
--intent-color: #7c3aed;
|
|
101
|
+
--intent-contrast: #ffffff;
|
|
102
|
+
--intent-hover: #6d28d9;
|
|
103
|
+
--intent-strong: light-dark(#5b21b6, #c4b5fd);
|
|
104
|
+
--intent-subtle: light-dark(#ede9fe, #4c1d95);
|
|
105
|
+
--intent-border: light-dark(#7c3aed, #a78bfa);
|
|
107
106
|
--intent-fill-max: 100%;
|
|
108
107
|
}
|
|
109
108
|
```
|
|
110
109
|
|
|
111
110
|
```html
|
|
112
|
-
<
|
|
111
|
+
<span class="badge beta">Beta</span> <button class="btn beta" type="button">Try the new editor</button>
|
|
113
112
|
```
|
|
114
113
|
|
|
115
|
-
|
|
114
|
+
These values measure 5.7:1 for white on the fill, 7.1:1 for white on the hover color, 8.61:1 (light) and 10.72:1 (dark) for the strong tone on the page, and 7.57:1 and 5.93:1 for the strong tone on the subtle tint.
|
|
115
|
+
|
|
116
|
+
**Set every slot**, including `--intent-fill-max`. Each component resets all seven slots to the neutral values at its own root, so a slot you leave out keeps neutral's value, and without `--intent-fill-max: 100%` your intent fills only to 20%, like neutral. What each slot does is in [Intent tokens](#intent-tokens).
|
|
117
|
+
|
|
118
|
+
The class works on everything that takes an intent: buttons, badges, fields and toggles, solid and ghost cards, progress bars, skeletons, tooltip bubbles, and the rest. A few behaviors are written for the six built-in names, and a custom intent does not get them:
|
|
119
|
+
|
|
120
|
+
- **A quiet, untinted rest.** A neutral `.card.soft`, `.panel`, and `.alert` rest on the quiet background tone, and they recognize an intent only by the six built-in classes. `.card.soft.beta`, `.panel.beta`, and `.alert.beta` are drawn like the neutral one: the quiet background tone instead of a violet tint. Your intent still colors their text and border.
|
|
121
|
+
- **The chip tint.** A `.beta` key cap or code block shows your `--intent-subtle` tint, but not the extra 12% of `--intent-color` a built-in intent adds over it.
|
|
122
|
+
- **Solo classes.** A [solo class](./solo.md) such as `.neobrutalism-solo` takes an intent only from the six built-in classes, so `.neobrutalism-solo.beta` is drawn neutral.
|
|
123
|
+
|
|
124
|
+
If you need those, there are two ways:
|
|
125
|
+
|
|
126
|
+
- **Retheme a built-in intent instead.** Set the `--color-info` family (or another one) to your colors, as in [Change the brand color](#change-the-brand-color), and write `.info`. Everything, including the cases above, then works. The cost is that the change reaches every `.info` inside the element you set it on, so set it on the narrowest element that works, and do not do it with an intent the page already uses for its own meaning.
|
|
127
|
+
- **Paint it yourself.** Write your own CSS for that one component, such as a `background-color` on `.panel.beta`.
|
|
128
|
+
|
|
129
|
+
> **Intent does not pass down.** Each component resets the intent slots at its own root, so a `.success` container does not recolor a destructive button inside it. Put the intent class on the element that shows the color.
|
|
130
|
+
|
|
131
|
+
## Color tokens
|
|
132
|
+
|
|
133
|
+
Every color token holds a light and a dark value through `light-dark()`; one value means both themes use it. Palette names such as `neutral-950` are Tailwind's default palette, which the package's compiled CSS declares for the colors it uses.
|
|
134
|
+
|
|
135
|
+
Each row is an override point: set it on `:root` to retheme the page, or on any element to retheme what is inside it. The `-hover`, `-subtle`, `-strong`, and `-contrast` rows are companions of their family's base color and do not follow it, so retheme the whole family. The `text` family has no `-subtle` row: the neutral intent takes its subtle tone from `--color-surface`.
|
|
136
|
+
|
|
137
|
+
| Token | Light, dark | Purpose |
|
|
138
|
+
| ------------------------------ | ---------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
139
|
+
| `--color-primary` | `neutral-950`, `neutral-50` | Fill of `.primary`. |
|
|
140
|
+
| `--color-primary-contrast` | `neutral-50`, `neutral-950` | Text and icons on a full primary fill. |
|
|
141
|
+
| `--color-primary-hover` | `neutral-700`, `neutral-200` | Primary fill under the pointer. |
|
|
142
|
+
| `--color-primary-subtle` | `neutral-200`, `neutral-900` | Primary tint behind soft components. |
|
|
143
|
+
| `--color-primary-strong` | `neutral-900`, `neutral-100` | Primary text, icons, and borders where the fill is not full. |
|
|
144
|
+
| `--color-accent` | `neutral-600`, `neutral-400` | Fill of `.secondary`. |
|
|
145
|
+
| `--color-accent-contrast` | `neutral-50`, `neutral-950` | Text and icons on a full secondary fill. |
|
|
146
|
+
| `--color-accent-hover` | `neutral-700`, `neutral-300` | Secondary fill under the pointer. |
|
|
147
|
+
| `--color-accent-subtle` | `neutral-100`, `neutral-800` | Secondary tint behind soft components. |
|
|
148
|
+
| `--color-accent-strong` | `neutral-800`, `neutral-200` | Secondary text, icons, and borders where the fill is not full. |
|
|
149
|
+
| `--color-border` | `neutral-400`, `neutral-700` | Border of neutral surfaces, tables, dividers, and key caps. |
|
|
150
|
+
| `--color-border-hover` | `neutral-600`, `neutral-500` | Border under the pointer. |
|
|
151
|
+
| `--color-control-border` | `neutral-500` | Resting border of neutral text controls and toggles, drawn at a fraction on text controls. |
|
|
152
|
+
| `--color-background` | `neutral-50`, `neutral-950` | The page. |
|
|
153
|
+
| `--color-foreground` | `neutral-100`, `neutral-900` | The quiet background tone one step off the page: neutral soft cards, panels, and alerts. |
|
|
154
|
+
| `--color-surface` | `neutral-200`, `neutral-800` | A further step: nested and muted surfaces, and the neutral intent's tint. |
|
|
155
|
+
| `--color-text` | `neutral-950`, `neutral-50` | Body text, and the neutral intent's color. |
|
|
156
|
+
| `--color-text-secondary` | `neutral-700`, `neutral-400` | Secondary text, such as `.hint`. |
|
|
157
|
+
| `--color-text-contrast` | `neutral-50`, `neutral-950` | Text on a full fill of `--color-text`, such as the mark of a checked neutral toggle. |
|
|
158
|
+
| `--color-text-hover` | `neutral-700`, `neutral-200` | Neutral color under the pointer. |
|
|
159
|
+
| `--color-text-strong` | `neutral-900`, `neutral-100` | Neutral text, icons, and borders where the fill is not full. |
|
|
160
|
+
| `--color-tooltip` | `white`, `neutral-700` | Background of a tooltip bubble with no intent. Chosen per theme so it reads as lifted in both. |
|
|
161
|
+
| `--color-tooltip-contrast` | `neutral-900`, `neutral-100` | Text on `--color-tooltip`. |
|
|
162
|
+
| `--color-success` | `emerald-700` | Fill of `.success`. |
|
|
163
|
+
| `--color-success-contrast` | `neutral-50` | Text on a full success fill: 5.14:1. |
|
|
164
|
+
| `--color-success-hover` | `#007552`, `#008e66` | Success fill under the pointer. |
|
|
165
|
+
| `--color-success-subtle` | `emerald-100`, `emerald-900` | Success tint behind soft components. |
|
|
166
|
+
| `--color-success-strong` | `emerald-800`, `emerald-300` | Success text, icons, and borders where the fill is not full. |
|
|
167
|
+
| `--color-warning` | `amber-600` | Fill of `.warning`. |
|
|
168
|
+
| `--color-warning-contrast` | `neutral-950` | Text on a full warning fill: near-black, not the page color. 6.19:1. |
|
|
169
|
+
| `--color-warning-hover` | `#d46700`, `#e78300` | Warning fill under the pointer. |
|
|
170
|
+
| `--color-warning-subtle` | `amber-100`, `amber-900` | Warning tint behind soft components. |
|
|
171
|
+
| `--color-warning-strong` | `amber-800`, `amber-300` | Warning text, icons, and borders where the fill is not full. |
|
|
172
|
+
| `--color-destructive` | `rose-700` | Fill of `.destructive`. |
|
|
173
|
+
| `--color-destructive-contrast` | `neutral-50` | Text on a full destructive fill: 5.78:1. |
|
|
174
|
+
| `--color-destructive-hover` | `#c00036`, `#d1054b` | Destructive fill under the pointer. |
|
|
175
|
+
| `--color-destructive-subtle` | `rose-100`, `rose-900` | Destructive tint behind soft components. |
|
|
176
|
+
| `--color-destructive-strong` | `rose-800`, `rose-300` | Destructive text, icons, and borders where the fill is not full. |
|
|
177
|
+
| `--color-info` | `indigo-600` | Fill of `.info`. |
|
|
178
|
+
| `--color-info-contrast` | `neutral-50` | Text on a full info fill: 6.19:1. |
|
|
179
|
+
| `--color-info-hover` | `#4b36e9`, `#5e4ff9` | Info fill under the pointer. |
|
|
180
|
+
| `--color-info-subtle` | `indigo-100`, `indigo-900` | Info tint behind soft components. |
|
|
181
|
+
| `--color-info-strong` | `indigo-800`, `indigo-300` | Info text, icons, and borders where the fill is not full. |
|
|
182
|
+
|
|
183
|
+
Theme changes belong in these values, not in component rules that check the theme.
|
|
184
|
+
|
|
185
|
+
## Intent tokens
|
|
186
|
+
|
|
187
|
+
An intent class sets these seven slots, and components read them. Because every component reads the same seven names, a class that sets all seven works as an intent, as [Your own intent](#your-own-intent) shows.
|
|
188
|
+
|
|
189
|
+
| Token | Purpose |
|
|
190
|
+
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
191
|
+
| `--intent-color` | The intent's base color, what a fill is made of. |
|
|
192
|
+
| `--intent-contrast` | Text on a full fill of `--intent-color`. |
|
|
193
|
+
| `--intent-hover` | The base color under the pointer. |
|
|
194
|
+
| `--intent-strong` | The intent as text, icon, or border wherever the fill is not full. |
|
|
195
|
+
| `--intent-subtle` | The light tint behind soft components and progress tracks. Neutral uses `--color-surface`. |
|
|
196
|
+
| `--intent-border` | Line color. With no intent it is the aesthetic's `--ui-ink`, then `--color-border`; text controls and toggles read `--ui-control-ink`, then `--ui-ink`, then `--color-control-border`, and tables read `--ui-rule-ink` first. |
|
|
197
|
+
| `--intent-fill-max` | How far a fill of this intent may go. `100%` for every intent except neutral. |
|
|
198
|
+
|
|
199
|
+
`--intent-color` and `--intent-strong` are not interchangeable. The base color is chosen to be filled with; the strong tone is chosen to be read against the page. A soft or ghost component prints the strong tone, which is why a soft warning reads in amber-800 while a solid one is filled with amber-600.
|
|
200
|
+
|
|
201
|
+
The strong tone also has to stay recognizably its own hue. On a dark page, the `-100` shade of every family is a pale tint with almost no color at small sizes: a soft success badge and a soft destructive one would both read as white. The dark strong tones are `-300` for that reason, and the tints under them are `-900`, which measures 5.0:1 or better wherever a partial fill holds text, and over 9:1 on the page.
|
|
202
|
+
|
|
203
|
+
`--intent-border` exists so a neutral border stays the quiet border gray rather than the text color. Everything that draws a line reads it: control borders, table rules, dividers, key caps, and quote bars.
|
|
204
|
+
|
|
205
|
+
`--intent-fill-max` exists for the neutral intent, whose color is the page's own text color. Every other intent is a hue, readable as a pale tint at 12% and saturated at 100%; a gray filled to 100% is a black or white block, the loudest thing on the page for the intent that means nothing in particular. Neutral stops at `20%`, so `.solid` gives it a quiet gray that is still a step past `.soft`. Hover adds its step on top of the cap, so a capped fill still deepens under the pointer.
|
|
206
|
+
|
|
207
|
+
The text color follows the fill. `--intent-contrast` is the text color for a full fill; printed on a fifth of one, it would be white on light gray. So contrast text appears only once the fill is past halfway, and reaches full strength at a full fill; below that, a component prints `--intent-strong`. A capped neutral therefore prints the strong tone. A state that lifts the cap on purpose, such as a checked checkbox, reaches a full fill and prints the contrast color.
|
|
116
208
|
|
|
117
209
|
## Foundation tokens
|
|
118
210
|
|
|
119
|
-
Foundation tokens
|
|
120
|
-
|
|
121
|
-
The four `--elevation-*`
|
|
122
|
-
|
|
123
|
-
| Token | Purpose
|
|
124
|
-
| -------------------------- |
|
|
125
|
-
| `--font-default` |
|
|
126
|
-
| `--container-narrow` |
|
|
127
|
-
| `--container-max` |
|
|
128
|
-
| `--container-wide` |
|
|
129
|
-
| `--layout-gutter` |
|
|
130
|
-
| `--layout-section-block` |
|
|
131
|
-
| `--layout-gap` |
|
|
132
|
-
| `--layout-grid-min` |
|
|
133
|
-
| `--radius-small` |
|
|
134
|
-
| `--radius-control` |
|
|
135
|
-
| `--radius-surface` |
|
|
136
|
-
| `--control-height` |
|
|
137
|
-
| `--border-width` |
|
|
138
|
-
| `--elevation-color` |
|
|
139
|
-
| `--elevation-none` | No shadow.
|
|
140
|
-
| `--elevation-sm` | A light shadow for your own
|
|
141
|
-
| `--elevation-md` | A shadow for your own raised elements, such as
|
|
142
|
-
| `--elevation-lg` | A shadow for your own
|
|
143
|
-
| `--focus-ring` |
|
|
144
|
-
| `--focus-ring-offset` |
|
|
145
|
-
| `--focus-ring-width` |
|
|
146
|
-
| `--motion-duration-fast` |
|
|
147
|
-
| `--motion-duration-normal` |
|
|
148
|
-
| `--motion-duration-slow` |
|
|
149
|
-
| `--motion-ease` |
|
|
150
|
-
| `--z-popover` |
|
|
151
|
-
| `--breakpoint-xs` |
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
211
|
+
Foundation tokens set layout, shape, motion, focus, depth, and stacking. Override them on `:root`, or on an element for what is inside it.
|
|
212
|
+
|
|
213
|
+
The four `--elevation-*` shadows are for elements you style yourself. They are separate from the `.flat`, `.raised`, and `.floating` classes, which scale a component's own shadow and draw nothing until an aesthetic or one of those classes asks for depth; see [Composing → Elevation](./composing.md#elevation). Both use the weights none, small, medium, and large, but one is a fixed value and the other scales shadow parts, so they do not always look the same.
|
|
214
|
+
|
|
215
|
+
| Token | Default | Purpose |
|
|
216
|
+
| -------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
|
|
217
|
+
| `--font-default` | `"Segoe UI", system-ui, sans-serif` | Page font. See [Fonts](#fonts). |
|
|
218
|
+
| `--container-narrow` | `48rem` | Width of `.section-content.narrow`. |
|
|
219
|
+
| `--container-max` | `80rem` | Width of `.section-content`. |
|
|
220
|
+
| `--container-wide` | `90rem` | Width of `.section-content.wide`. |
|
|
221
|
+
| `--layout-gutter` | `clamp(1rem, 4vw, 2rem)` | Side padding of `.section`, growing with the window. |
|
|
222
|
+
| `--layout-section-block` | `clamp(4rem, 9vw, 7rem)` | Top and bottom padding of `.section`, growing with the window. |
|
|
223
|
+
| `--layout-gap` | `1rem` | Gap of `.view`, `.stack`, `.cluster`, and `.auto-grid`. |
|
|
224
|
+
| `--layout-grid-min` | `16rem` | Narrowest column of `.auto-grid`. |
|
|
225
|
+
| `--radius-small` | `0.25rem` | Corner of small chips: `.kbd` and `.code`. |
|
|
226
|
+
| `--radius-control` | `0.5rem` | Corner of buttons, fields, and tooltip bubbles. |
|
|
227
|
+
| `--radius-surface` | `0.875rem` | Corner of cards, panels, and alerts. |
|
|
228
|
+
| `--control-height` | `2.5rem` | Minimum height of a default button and a text control. |
|
|
229
|
+
| `--border-width` | `1px` | Border width. |
|
|
230
|
+
| `--elevation-color` | `rgb(15 23 42 / 0.08)` light, `rgb(0 0 0 / 0.55)` dark | The shadow color the four elevations use. Heavier on a dark page, where a light shadow would not show. |
|
|
231
|
+
| `--elevation-none` | `none` | No shadow. |
|
|
232
|
+
| `--elevation-sm` | `0 1px 2px`, `0 1px 3px` | A light shadow for your own surfaces, such as a card. |
|
|
233
|
+
| `--elevation-md` | `0 4px 6px -1px`, `0 2px 4px -2px` | A shadow for your own raised elements, such as a dropdown menu. |
|
|
234
|
+
| `--elevation-lg` | `0 20px 25px -5px`, `0 8px 10px -6px` | A shadow for your own overlays, such as a modal dialog. |
|
|
235
|
+
| `--focus-ring` | `--color-primary` at 64% opacity | Color of the keyboard focus ring. |
|
|
236
|
+
| `--focus-ring-offset` | Not set | Distance of the ring from the element. When unset, the ring sits on the element's border under every aesthetic. |
|
|
237
|
+
| `--focus-ring-width` | `3px` | Width of the keyboard focus ring. |
|
|
238
|
+
| `--motion-duration-fast` | `120ms` | A table row's hover. |
|
|
239
|
+
| `--motion-duration-normal` | `200ms` | Color, border, shadow, and press transitions, toggle marks, and the tooltip bubble. |
|
|
240
|
+
| `--motion-duration-slow` | `400ms` | Progress value changes, and the base of the skeleton and progress shimmer cycle. |
|
|
241
|
+
| `--motion-ease` | `cubic-bezier(0.2, 0, 0, 1)` | Easing for every transition. |
|
|
242
|
+
| `--z-popover` | `40` | Stacking order of tooltip bubbles. Use it for your own popovers so they stack the same way. |
|
|
243
|
+
| `--breakpoint-xs` | `30rem` | The `xs:` responsive breakpoint. Only in a `/tw` build; the compiled entrypoints do not declare it. |
|
|
244
|
+
|
|
245
|
+
Each `--elevation-*` shadow is made of the listed parts, each in `--elevation-color`. The hover step that deepens a fill under the pointer is a presentation token, `--hover-step`; see [Customizing](./customizing.md#presentation-tokens).
|
|
246
|
+
|
|
247
|
+
## Fonts
|
|
248
|
+
|
|
249
|
+
The package ships no font files and makes no network requests. Every font token names fonts already installed on the reader's device until you supply your own.
|
|
250
|
+
|
|
251
|
+
| Token | Read by | Without your value |
|
|
252
|
+
| ---------------- | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
253
|
+
| `--font-default` | The reset, on `html` and `body`. Buttons and form controls inherit it. | `"Segoe UI", system-ui, sans-serif` |
|
|
254
|
+
| `--font-mono` | The `kbd`, `code`, and `pre` content helpers, and `<kbd>`, `<code>`, and `<pre>` under `/native` | `ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace`. Under `/tw`, your Tailwind theme's value. |
|
|
255
|
+
| `--font-pixel` | [`.pixel`](./aesthetics.md#pixel) and `.pixel-solo` | Not declared. Falls back to a monospace stack. |
|
|
256
|
+
| `--font-rounded` | [`.chunky-tile`](./aesthetics.md#chunky-tile) and `.chunky-tile-solo` | Not declared. Falls back to `--font-default`, then a sans-serif stack. |
|
|
257
|
+
| `--font-cyber` | [`.cyber`](./aesthetics.md#cyber) and `.cyber-solo` | Not declared. Falls back to a monospace stack. |
|
|
258
|
+
| `--font-sketch` | [`.sketch`](./aesthetics.md#sketch) and `.sketch-solo` | Not declared. Falls back to the platform `cursive` family. |
|
|
259
|
+
|
|
260
|
+
`--font-default` reaches the page only through the reset, which `@codenhub/styles`, `/native`, `/tw`, `/tw/native`, and `/tw/reset` include. With `/theme` or `/components` alone, set `font-family` on `body` yourself. The aesthetic tokens are read by the aesthetic's own class, so they work with any entrypoint.
|
|
261
|
+
|
|
262
|
+
To use a web font, load it the way you load any font, then name it in the token. Set the token on `:root` for the whole page, or on any element for that part of it:
|
|
263
|
+
|
|
264
|
+
```html
|
|
265
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
266
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
267
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400..700&display=swap" />
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
```css
|
|
271
|
+
:root {
|
|
272
|
+
--font-default: "Inter", system-ui, sans-serif;
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
A self-hosted font is declared with `@font-face` and named the same way:
|
|
277
|
+
|
|
278
|
+
```css
|
|
279
|
+
@font-face {
|
|
280
|
+
font-family: "Pixelify Sans";
|
|
281
|
+
src: url("/fonts/pixelify-sans.woff2") format("woff2");
|
|
282
|
+
font-weight: 400 700;
|
|
283
|
+
font-display: swap;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
:root {
|
|
287
|
+
--font-pixel: "Pixelify Sans", monospace;
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Load weights 400 to 700, and 800 for `--font-rounded`: components set `font-weight` from 400 to 700, and `.chunky-tile` sets its labels in 800. A browser that lacks a weight fakes it by thickening the regular one, which smears a pixel or handwriting face. Always end the stack with a generic family, such as `sans-serif` or `monospace`, so text still renders while the font loads or if it fails to.
|
|
292
|
+
|
|
293
|
+
## Next
|
|
294
|
+
|
|
295
|
+
The screen has your colors in both themes. [Aesthetics](./aesthetics.md) changes what it is made of: thick black outlines, frosted glass, pixels, and more.
|