@codenhub/styles 0.6.0 → 0.8.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 +62 -0
- package/README.md +28 -22
- package/README.pt-BR.md +62 -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/cli.js +189 -0
- package/dist/components.css +2 -2
- package/dist/index.css +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/native.css +2 -2
- package/dist/palette.css +1 -1
- package/dist/theme.css +2 -2
- package/docs/accessibility.md +108 -60
- 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 +2 -1
- package/docs/changelog/0.7.0.md +50 -0
- package/docs/changelog/0.8.0.md +70 -0
- package/docs/changelog/index.md +2 -0
- package/docs/concepts.md +188 -46
- package/docs/es/accessibility.md +169 -0
- package/docs/es/concepts.md +212 -0
- package/docs/es/index.md +105 -0
- package/docs/es/integrating/astro.md +35 -0
- package/docs/es/integrating/index.md +75 -0
- package/docs/es/integrating/nextjs.md +67 -0
- package/docs/es/integrating/svelte.md +45 -0
- package/docs/es/integrating/tailwind.md +148 -0
- package/docs/es/integrating/vue.md +31 -0
- package/docs/es/integrating/without-a-bundler.md +238 -0
- package/docs/es/setup.md +188 -0
- package/docs/es/usage/aesthetics.md +282 -0
- package/docs/es/usage/buttons.md +135 -0
- package/docs/es/usage/composing.md +168 -0
- package/docs/es/usage/content-and-layout.md +219 -0
- package/docs/es/usage/customizing.md +304 -0
- package/docs/es/usage/feedback.md +157 -0
- package/docs/es/usage/forms.md +256 -0
- package/docs/es/usage/index.md +33 -0
- package/docs/es/usage/presets.md +92 -0
- package/docs/es/usage/solo.md +86 -0
- package/docs/es/usage/theming.md +309 -0
- package/docs/es/usage/tooltips.md +127 -0
- package/docs/index.md +86 -26
- package/docs/integrating/astro.md +3 -4
- package/docs/integrating/index.md +46 -13
- package/docs/integrating/nextjs.md +3 -4
- package/docs/integrating/svelte.md +5 -4
- package/docs/integrating/tailwind.md +89 -6
- package/docs/integrating/vue.md +3 -4
- package/docs/integrating/without-a-bundler.md +237 -0
- package/docs/pt-BR/accessibility.md +169 -0
- package/docs/pt-BR/concepts.md +212 -0
- package/docs/pt-BR/index.md +105 -0
- package/docs/pt-BR/integrating/astro.md +35 -0
- package/docs/pt-BR/integrating/index.md +75 -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 +148 -0
- package/docs/pt-BR/integrating/vue.md +31 -0
- package/docs/pt-BR/integrating/without-a-bundler.md +238 -0
- package/docs/pt-BR/setup.md +188 -0
- package/docs/pt-BR/usage/aesthetics.md +282 -0
- package/docs/pt-BR/usage/buttons.md +135 -0
- package/docs/pt-BR/usage/composing.md +168 -0
- package/docs/pt-BR/usage/content-and-layout.md +219 -0
- package/docs/pt-BR/usage/customizing.md +304 -0
- package/docs/pt-BR/usage/feedback.md +157 -0
- package/docs/pt-BR/usage/forms.md +256 -0
- package/docs/pt-BR/usage/index.md +33 -0
- package/docs/pt-BR/usage/presets.md +92 -0
- package/docs/pt-BR/usage/solo.md +86 -0
- package/docs/pt-BR/usage/theming.md +309 -0
- package/docs/pt-BR/usage/tooltips.md +127 -0
- package/docs/setup.md +142 -91
- package/docs/usage/aesthetics.md +89 -73
- package/docs/usage/buttons.md +112 -40
- package/docs/usage/composing.md +109 -92
- package/docs/usage/content-and-layout.md +160 -125
- package/docs/usage/customizing.md +117 -41
- package/docs/usage/feedback.md +138 -71
- package/docs/usage/forms.md +201 -107
- package/docs/usage/index.md +22 -14
- package/docs/usage/presets.md +91 -0
- package/docs/usage/solo.md +85 -0
- package/docs/usage/theming.md +273 -118
- package/docs/usage/tooltips.md +90 -49
- package/llms-full.txt +2820 -1298
- package/llms.txt +24 -22
- package/package.json +134 -91
- package/{dist/tw → tw}/aesthetics/chunky-tile.css +107 -29
- package/{dist/tw → tw}/aesthetics/cyber.css +88 -40
- package/{dist/tw → tw}/aesthetics/glass.css +257 -61
- package/{dist/tw → tw}/aesthetics/neobrutalism.css +113 -20
- package/{dist/tw → tw}/aesthetics/pixel.css +93 -8
- package/tw/aesthetics/sketch.css +417 -0
- package/{dist/tw → tw}/box.css +105 -9
- package/tw/components/button.css +11 -0
- package/tw/components/button.rules.css +187 -0
- package/tw/components/feedback.css +11 -0
- package/{dist/tw/components/feedback.css → tw/components/feedback.rules.css} +136 -32
- package/tw/components/form.css +11 -0
- package/{dist/tw/components/form.css → tw/components/form.rules.css} +577 -125
- package/tw/components/index.css +16 -0
- package/tw/components/rules.css +41 -0
- package/tw/components/surface.css +11 -0
- package/tw/components/surface.rules.css +222 -0
- package/tw/components/tooltip.css +11 -0
- package/{dist/tw/components/tooltip.css → tw/components/tooltip.rules.css} +43 -27
- package/{dist/tw → tw}/corner.css +18 -12
- package/{dist/tw → tw}/elevation.css +23 -17
- package/{dist/tw → tw}/index.css +12 -10
- package/tw/index.d.ts +1 -0
- package/tw/intent.css +312 -0
- package/tw/modifiers.css +127 -0
- package/tw/native.css +320 -0
- package/tw/presentation.css +139 -0
- package/tw/reset.css +10 -0
- package/{dist/tw/reset.css → tw/reset.rules.css} +21 -22
- package/tw/size.css +34 -0
- package/tw/surface.css +9 -0
- package/tw/surface.rules.css +212 -0
- package/{dist/tw → tw}/theme.css +121 -45
- package/tw/typography.css +8 -0
- package/{dist/tw/typography.css → tw/typography.rules.css} +0 -3
- package/{dist/tw → tw}/utilities/content.css +212 -50
- package/tw/utilities/index.css +11 -0
- package/tw/utilities/layout.css +208 -0
- package/tw/utilities/rules.css +8 -0
- package/dist/tw/aesthetics/sketch.css +0 -333
- package/dist/tw/components/button.css +0 -139
- package/dist/tw/components/index.css +0 -36
- package/dist/tw/components/loader.css +0 -116
- package/dist/tw/components/surface.css +0 -175
- package/dist/tw/intent.css +0 -228
- package/dist/tw/native.css +0 -203
- package/dist/tw/palette.css +0 -460
- package/dist/tw/presentation.css +0 -68
- package/dist/tw/surface.css +0 -61
- package/dist/tw/utilities/index.css +0 -6
- package/dist/tw/utilities/layout.css +0 -130
- /package/{dist/tw → tw}/aesthetics/index.css +0 -0
package/docs/usage/forms.md
CHANGED
|
@@ -1,161 +1,255 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Forms
|
|
3
|
-
description:
|
|
4
|
-
order:
|
|
3
|
+
description: Labeled fields, hints and errors, icons and fixed prefixes, selects, and checkbox, radio, and switch toggles.
|
|
4
|
+
order: 2
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Forms
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
| `.hint.destructive` | Helper text with destructive intent. |
|
|
15
|
-
| `.surface` | Shared public container composition utility. |
|
|
16
|
-
| `.text-control` | Shared public text-control composition utility. |
|
|
17
|
-
| `.ipt` | Input control styling. |
|
|
18
|
-
| `.input-group` | Wrapper that owns the field box so a control can carry an icon or affix. |
|
|
19
|
-
| `.unadorned` | Removes the browser's own field decorations, on the control or on its `.input-group`. |
|
|
20
|
-
| `.textarea` | Textarea control styling. |
|
|
21
|
-
| `.select` | Select control styling. With `multiple` or a `size` above 1 it is a list box: no chevron, as tall as its rows. |
|
|
22
|
-
| `input[type="checkbox"].checkbox` | Custom checkbox control styling. |
|
|
23
|
-
| `input[type="radio"].radio` | Custom radio control styling. |
|
|
24
|
-
| `input[type="checkbox"].switch` | Custom switch control styling. |
|
|
25
|
-
| `[aria-invalid="true"]` on controls | Destructive border and focus color. |
|
|
26
|
-
| `[disabled]`, `[aria-disabled="true"]`, `[data-disabled]` on controls | Disabled styling. |
|
|
27
|
-
|
|
28
|
-
## Icons
|
|
29
|
-
|
|
30
|
-
The package ships no icon for text inputs. Icons for `.input-group` are the consumer's to choose: artwork painted as a `data:` URI could not read `currentColor` or a custom property, so it could not follow the theme or fit every aesthetic. The toggle marks below are the exception: small, fixed, built-in glyphs. `.alert` likewise takes a consumer-supplied icon; see [Feedback](./feedback.md#example).
|
|
31
|
-
|
|
32
|
-
`.input-group` is the wrapper for a control that carries one. It owns the field box — border, radius, fill, focus ring, invalid and disabled state — and the control inside it goes flush, so the boundary is drawn once. Any icon element works, placed before the control for a leading icon or after it for a trailing one: an inline `<svg>`, an `<img>`, or a class from an icon set such as `@codenhub/icons`.
|
|
9
|
+
The profile card has a Save button but nothing to save. This page fills it in: a display name with a hint, an email address that shows a validation error, a profile address with a fixed prefix, a language select, and the toggles for notifications, billing, and profile visibility. The package styles each control; your HTML provides the labels, the validation, and the error messages, and this page shows how to connect them.
|
|
10
|
+
|
|
11
|
+
## A labeled field
|
|
12
|
+
|
|
13
|
+
A field is a label, a control, and an optional hint, stacked:
|
|
33
14
|
|
|
34
15
|
```html
|
|
35
16
|
<div class="field">
|
|
36
|
-
<label class="label" for="
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
17
|
+
<label class="label" for="display-name">Display name</label>
|
|
18
|
+
<input class="ipt" id="display-name" name="display-name" aria-describedby="display-name-hint" />
|
|
19
|
+
<span class="hint" id="display-name-hint">Shown on invoices and shared projects.</span>
|
|
20
|
+
</div>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- `.field` stacks its children with a small gap (0.35rem) and takes the full width.
|
|
24
|
+
- `.label` sets label text: 1rem, medium weight.
|
|
25
|
+
- `.hint` is smaller, secondary-colored helper text. Keep it outside the `<label>` and point `aria-describedby` at it, so a screen reader announces it as a description instead of reading it as part of the field's name.
|
|
26
|
+
- `.ipt` styles an `<input>`. Use `.textarea` for a `<textarea>` and `.select` for a `<select>`.
|
|
27
|
+
|
|
28
|
+
A text control is at least 2.5rem tall (`--control-height`), the same height as a default button, so a field and a button line up in a row. Its default look is no fill and a border. A `.textarea` is at least 7rem tall and can be resized vertically.
|
|
29
|
+
|
|
30
|
+
### Sizes
|
|
31
|
+
|
|
32
|
+
`.ipt`, `.select`, `.textarea`, and `.input-group` take the button's size classes, so a small field and a small button line up in a row:
|
|
33
|
+
|
|
34
|
+
| Class | Height | Side padding | Text |
|
|
35
|
+
| ------- | ------ | ------------ | --------- |
|
|
36
|
+
| `.sm` | 2rem | 0.625rem | 0.875rem |
|
|
37
|
+
| default | 2.5rem | 0.75rem | inherited |
|
|
38
|
+
| `.lg` | 3rem | 1rem | 1.0625rem |
|
|
39
|
+
|
|
40
|
+
The corners scale with the size, as a button's do. A `.textarea` keeps its 7rem minimum height at every size; the class changes its text, padding, and corners. Size an `.input-group` on the group, not on the control inside it: the control and its adornments take the group's text size.
|
|
41
|
+
|
|
42
|
+
```html
|
|
43
|
+
<div class="cluster tight">
|
|
44
|
+
<input class="ipt sm" aria-label="Coupon code" />
|
|
45
|
+
<button class="btn sm" type="button">Apply</button>
|
|
46
|
+
</div>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Show a validation error
|
|
50
|
+
|
|
51
|
+
Mark the control invalid with `aria-invalid="true"` and give the error message `.hint.destructive`:
|
|
52
|
+
|
|
53
|
+
```html
|
|
54
|
+
<div class="field">
|
|
55
|
+
<label class="label" for="email">Email</label>
|
|
56
|
+
<input class="ipt" type="email" id="email" name="email" value="ada@" aria-invalid="true" aria-describedby="email-error" />
|
|
57
|
+
<span class="hint destructive" id="email-error">Enter a full email address, such as ada@example.com.</span>
|
|
58
|
+
</div>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
An invalid control draws its border, focus ring, and typed text in the destructive color, whatever intent class it has. The text uses the readable tone of that color, `--intent-strong`, so it stays legible on the page. The package only paints the state: deciding that the value is invalid, setting and clearing `aria-invalid`, and writing the message are your code. Remove `aria-invalid` once the value is valid again; leaving it set keeps the field red. On a checkbox, radio, or switch, `aria-invalid="true"` draws the toggle exactly as `.destructive` does, checked mark included.
|
|
62
|
+
|
|
63
|
+
A hint takes any of the six built-in intents, not only `.destructive`: `.hint.success` confirms a value was accepted, and `.hint.warning` flags one that is allowed but unusual. Each prints in its intent's readable tone, `--intent-strong`, which holds 4.5:1 against the page in both themes. A hint with no intent, with `.neutral`, or with an [intent you defined yourself](./theming.md#your-own-intent), stays secondary-colored. Only a class on the hint itself colors it; an intent on the field or a container around it does not.
|
|
64
|
+
|
|
65
|
+
```html
|
|
66
|
+
<input class="ipt success" id="username" value="ada" aria-describedby="username-hint" /> <span class="hint success" id="username-hint">That username is available.</span>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Put the profile form together
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<form class="card stack" aria-labelledby="profile-title">
|
|
73
|
+
<h2 class="text-title-sm" id="profile-title">Profile</h2>
|
|
74
|
+
|
|
75
|
+
<div class="field">
|
|
76
|
+
<label class="label" for="display-name">Display name</label>
|
|
77
|
+
<input class="ipt" id="display-name" name="display-name" value="Ada Lovelace" aria-describedby="display-name-hint" />
|
|
78
|
+
<span class="hint" id="display-name-hint">Shown on invoices and shared projects.</span>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<div class="field">
|
|
82
|
+
<label class="label" for="email">Email</label>
|
|
83
|
+
<input class="ipt" type="email" id="email" name="email" value="ada@example.com" />
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div class="field">
|
|
87
|
+
<label class="label" for="bio">Bio</label>
|
|
88
|
+
<textarea class="textarea" id="bio" name="bio" rows="3"></textarea>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<div class="field">
|
|
92
|
+
<label class="label" for="language">Language</label>
|
|
93
|
+
<select class="select" id="language" name="language">
|
|
94
|
+
<option>English</option>
|
|
95
|
+
<option>Português</option>
|
|
96
|
+
<option>Español</option>
|
|
97
|
+
</select>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div class="cluster">
|
|
101
|
+
<button class="btn primary" type="submit">Save changes</button>
|
|
102
|
+
<button class="btn ghost" type="reset">Cancel</button>
|
|
103
|
+
</div>
|
|
104
|
+
</form>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
A `.select` draws its own arrow. With `multiple` or a `size` above 1 it becomes a list box instead: no arrow, as tall as the rows it shows. The open list of options is drawn by the browser and the operating system, so it does not take the package's look.
|
|
108
|
+
|
|
109
|
+
## Add an icon or a fixed prefix
|
|
110
|
+
|
|
111
|
+
`.input-group` puts an icon or a piece of text inside a field's border. The group draws the border, background, focus ring, and invalid and disabled states; the control inside it gives up its own, so the border is drawn once. Place the adornment before the control to put it at the start, after it to put it at the end. A group is the height of a lone field, so it lines up with the fields and buttons beside it.
|
|
112
|
+
|
|
113
|
+
The profile address always starts with the same host, so it is a fixed prefix:
|
|
114
|
+
|
|
115
|
+
```html
|
|
116
|
+
<div class="field">
|
|
117
|
+
<label class="label" for="profile-url">Profile address</label>
|
|
118
|
+
<div class="input-group" style="--input-group-gap: 0">
|
|
119
|
+
<span>app.example.com/u/</span>
|
|
120
|
+
<input class="ipt" id="profile-url" name="profile-url" value="ada" />
|
|
43
121
|
</div>
|
|
44
122
|
</div>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The gap between the control and its adornment is `--input-group-gap`, 0.5rem by default. That suits an icon, but text meant to read as part of the value looks broken with a space after it, so the example sets it to `0`. Set it on the `.input-group` itself: the group declares its own default, so a value set on a parent element has no effect. It is one of six [public component variables](./customizing.md#component-variables).
|
|
126
|
+
|
|
127
|
+
A members search, with an icon at the start (the `ic-lucide-*` classes need `@codenhub/icons` loaded; see [Buttons → Loading icons](./buttons.md#loading-icons)):
|
|
128
|
+
|
|
129
|
+
```html
|
|
45
130
|
<div class="field">
|
|
46
|
-
<label class="label" for="
|
|
131
|
+
<label class="label" for="member-search">Find a member</label>
|
|
47
132
|
<div class="input-group">
|
|
48
|
-
<
|
|
49
|
-
<
|
|
133
|
+
<i class="ic-lucide-search" aria-hidden="true"></i>
|
|
134
|
+
<input class="ipt" type="search" id="member-search" name="q" />
|
|
50
135
|
</div>
|
|
51
136
|
</div>
|
|
52
137
|
```
|
|
53
138
|
|
|
54
|
-
|
|
139
|
+
A `.select` works in a group too. The group removes the control's side padding, except at the end of a single-row select, which keeps 1.75rem so the chosen option's text does not run under the arrow.
|
|
55
140
|
|
|
56
|
-
|
|
141
|
+
Any element works as the adornment: an icon class, an inline `<svg>`, an `<img>`, or text. The package ships no icons for fields, because a built-in image could not follow your text color, theme, or aesthetic.
|
|
57
142
|
|
|
58
|
-
`.
|
|
143
|
+
The group reads intent and presentation the way a lone `.ipt` does: `.input-group.primary` colors the border and the typed text, and `.input-group.soft.edgeless` is a field sunk into the page. Put the intent on the group, not on the control inside: the group draws the field, so the control's text takes the group's intent and an intent class on the control has no effect. `aria-invalid="true"` or `disabled` on the control inside applies to the whole group, and so does either on the group itself. The group's focus ring appears when its field has focus, so unlike a lone field it also shows after a mouse click. A button inside the group, such as a clear button, draws its own ring when it has focus, and the group draws none: one ring always marks the one control that has focus.
|
|
144
|
+
|
|
145
|
+
## Browser decorations
|
|
146
|
+
|
|
147
|
+
Some input types come with built-in buttons: a date or time field's picker button, a number field's up and down arrows, and a search field's clear button. The package keeps them, because each one also does something: the picker button is the only way to open the picker with a mouse, and the clear button empties the field.
|
|
148
|
+
|
|
149
|
+
`.unadorned` removes them, for a field where you draw your own. Put it on the control, or on its `.input-group`. Removing a decoration removes what it did, so connect your replacement yourself: `input.showPicker()` opens a picker, `stepUp()` and `stepDown()` replace the arrows, and setting `value` to `""` and dispatching an `input` event replaces a clear button. Typing keeps working either way. Firefox gives no way to remove its date picker button, so it stays there.
|
|
59
150
|
|
|
60
151
|
```html
|
|
61
152
|
<div class="field">
|
|
62
|
-
<label class="label" for="
|
|
153
|
+
<label class="label" for="member-filter">Find a member</label>
|
|
63
154
|
<div class="input-group unadorned">
|
|
64
|
-
<i class="ic-search" aria-hidden="true"></i>
|
|
65
|
-
<input class="ipt" type="search" id="
|
|
66
|
-
<button
|
|
67
|
-
<i class="ic-x" aria-hidden="true"></i>
|
|
155
|
+
<i class="ic-lucide-search" aria-hidden="true"></i>
|
|
156
|
+
<input class="ipt" type="search" id="member-filter" name="q" />
|
|
157
|
+
<button class="btn icon ghost p-xs" type="button" aria-label="Clear search">
|
|
158
|
+
<i class="ic-lucide-x" aria-hidden="true"></i>
|
|
68
159
|
</button>
|
|
69
160
|
</div>
|
|
70
161
|
</div>
|
|
71
162
|
```
|
|
72
163
|
|
|
73
|
-
The
|
|
164
|
+
The clear button above is a real `<button>` with an accessible name. A button inside a group keeps its own classes: a `.btn.ghost` has no fill and, like every button by default, no border, so it sits inside the field's border without drawing one of its own.
|
|
165
|
+
|
|
166
|
+
## Toggles
|
|
167
|
+
|
|
168
|
+
The settings screen has three kinds of toggle: a checkbox to opt into invoice emails, radio buttons to choose a billing period, and a switch to make the profile public. Each class goes on a native `<input>` of the matching type:
|
|
74
169
|
|
|
75
170
|
```html
|
|
76
|
-
<
|
|
77
|
-
<
|
|
78
|
-
<
|
|
79
|
-
|
|
171
|
+
<fieldset class="stack tight">
|
|
172
|
+
<legend class="label">Notifications</legend>
|
|
173
|
+
<label class="cluster tight">
|
|
174
|
+
<input class="checkbox" type="checkbox" name="invoice-email" checked />
|
|
175
|
+
Email me when an invoice is ready
|
|
176
|
+
</label>
|
|
177
|
+
</fieldset>
|
|
178
|
+
|
|
179
|
+
<fieldset class="stack tight">
|
|
180
|
+
<legend class="label">Billing period</legend>
|
|
181
|
+
<label class="cluster tight">
|
|
182
|
+
<input class="radio" type="radio" name="period" value="monthly" />
|
|
183
|
+
Monthly
|
|
184
|
+
</label>
|
|
185
|
+
<label class="cluster tight">
|
|
186
|
+
<input class="radio" type="radio" name="period" value="yearly" checked />
|
|
187
|
+
Yearly, two months free
|
|
188
|
+
</label>
|
|
189
|
+
</fieldset>
|
|
190
|
+
|
|
191
|
+
<label class="cluster tight">
|
|
192
|
+
<input class="switch primary" type="checkbox" role="switch" name="public-profile" />
|
|
193
|
+
Public profile
|
|
194
|
+
</label>
|
|
80
195
|
```
|
|
81
196
|
|
|
82
|
-
|
|
197
|
+
- `.checkbox` goes on `type="checkbox"`, `.radio` on `type="radio"`, and `.switch` on `type="checkbox"`. Give a switch `role="switch"` yourself, so it is announced as on or off rather than checked.
|
|
198
|
+
- `.cluster.tight` on the `<label>` lines the control up with its text and leaves a 0.5rem gap.
|
|
199
|
+
- A checkbox whose `indeterminate` property is set, for a group where only some items are checked, shows a dash, and keeps the dash while also `checked`, as the browser's own checkbox does. Set it from script (`input.indeterminate = true`); there is no attribute for it.
|
|
83
200
|
|
|
84
|
-
|
|
201
|
+
### Checked and unchecked colors
|
|
85
202
|
|
|
86
|
-
|
|
203
|
+
An intent class sets the checked color. With no intent, a checked toggle is filled with the text color, and the mark is drawn in the page color: a black box with a white check on a light page. Unlike a neutral button, a neutral toggle fills all the way when checked.
|
|
87
204
|
|
|
88
|
-
|
|
89
|
-
| ---------------------- | ----------------------- |
|
|
90
|
-
| `.neutral` _(default)_ | Text color, capped. |
|
|
91
|
-
| `.primary` | Primary color. |
|
|
92
|
-
| `.secondary` | Secondary/accent color. |
|
|
93
|
-
| `.success` | Success color. |
|
|
94
|
-
| `.warning` | Warning color. |
|
|
95
|
-
| `.destructive` | Destructive color. |
|
|
96
|
-
| `.info` | Info color. |
|
|
205
|
+
Presentation changes only the unchecked look. Every toggle rests at `.soft`; once checked, each has one look whatever its presentation:
|
|
97
206
|
|
|
98
|
-
|
|
207
|
+
| Toggle | Unchecked fill | Checked |
|
|
208
|
+
| ---------------- | -------------- | ---------------------------------------------- |
|
|
209
|
+
| `.ghost` | 0% | 100% fill, with the mark in the contrast color |
|
|
210
|
+
| `.soft`, default | 12% | 100% fill, with the mark in the contrast color |
|
|
211
|
+
| `.solid` | 40% | 100% fill, with the mark in the contrast color |
|
|
99
212
|
|
|
100
|
-
|
|
101
|
-
| ---------------- | --------- | ---------------------------------------- |
|
|
102
|
-
| `.ghost` | 0% | 100%, mark in the contrast tone (pinned) |
|
|
103
|
-
| `.soft`, default | 12% | 100%, mark in the contrast tone (pinned) |
|
|
104
|
-
| `.solid` | 40% | 100%, mark in the contrast tone (pinned) |
|
|
213
|
+
A checked checkbox and a checked switch cut their mark out of the filled plate. A checked radio thickens its ring to twice the resting line width, up to 3px, takes the full intent color on it, and shows a dot. The 3px limit keeps the ring from swallowing the dot under an aesthetic with a thick line.
|
|
105
214
|
|
|
106
|
-
|
|
215
|
+
`.checkbox` and `.radio` always draw their border, even with `.edgeless`, because the border is the only thing that shows an unchecked box. `.switch.ghost` keeps its border too, since with no fill and no border nothing would mark the track. These are listed in [Composing](./composing.md#component-axis-reference).
|
|
107
216
|
|
|
108
|
-
|
|
217
|
+
An aesthetic that draws its border as an inner shadow, such as `.pixel`, cannot make that shadow wider than the toggle's border width. A 16px checkbox or a 20px switch has no room for a thicker inner ring without covering the mark. This only matters if you set `--ui-shadow-spread` yourself; see [Customizing → Material tokens](./customizing.md#material-tokens).
|
|
109
218
|
|
|
110
|
-
##
|
|
219
|
+
## Fill and border on text controls
|
|
111
220
|
|
|
112
|
-
Text controls
|
|
221
|
+
Text controls take intent, which colors the border, the focus ring, and the typed text, the text in the intent's readable tone (`--intent-strong`). They also take both presentation axes. Their fill is capped low, so typed text stays readable:
|
|
113
222
|
|
|
114
|
-
|
|
223
|
+
| On a text control | Fill |
|
|
224
|
+
| ----------------------------------------------- | ---- |
|
|
225
|
+
| `.ghost`, default | 0% |
|
|
226
|
+
| Any fill from a container (`.soft` or `.solid`) | 6% |
|
|
227
|
+
| `.soft` on the control | 12% |
|
|
228
|
+
| `.solid` on the control | 20% |
|
|
229
|
+
|
|
230
|
+
A container's fill is meant for the surfaces in it, so a field nobody classed takes only a faint 6% of it. Put the class on the field itself for more.
|
|
231
|
+
|
|
232
|
+
The border works the same way. An `.edgeless` inherited from a container is ignored, so a toolbar cannot leave a field with no visible edge. `.edgeless` written on the control itself is honored: that is how you ask for a borderless field. A borderless field does not meet the WCAG 1.4.11 contrast requirement for a control's boundary, so it is never a default; its focus ring still shows.
|
|
115
233
|
|
|
116
234
|
```html
|
|
117
|
-
<input class="ipt success" placeholder="
|
|
118
|
-
<input class="ipt
|
|
119
|
-
<input class="ipt soft edged" placeholder="Tinted with a border" />
|
|
235
|
+
<input class="ipt success" placeholder="Matches your current password" />
|
|
236
|
+
<input class="ipt soft edged" placeholder="Tinted, with a border" />
|
|
120
237
|
<input class="ipt soft edgeless" placeholder="Sunk into the page" />
|
|
121
238
|
<div class="soft">
|
|
122
|
-
<input class="ipt" placeholder="
|
|
123
|
-
</div>
|
|
124
|
-
<div class="edgeless">
|
|
125
|
-
<input class="ipt" placeholder="Keeps its line; the floor holds" />
|
|
239
|
+
<input class="ipt" placeholder="A container's .soft gives a 6% tint" />
|
|
126
240
|
</div>
|
|
127
241
|
```
|
|
128
242
|
|
|
129
|
-
|
|
243
|
+
At rest, a field's border is deliberately lighter than 3:1 against the page, so hover and focus have a visible change to make. [Accessibility → Control boundaries](../accessibility.md#control-boundaries) explains the trade-off and how to get a stronger border.
|
|
130
244
|
|
|
131
|
-
|
|
132
|
-
<div class="surface glass">Blurred, translucent, glass corners</div>
|
|
133
|
-
<div class="surface pixel">Cut corners and an inset ring</div>
|
|
134
|
-
<div class="surface primary solid">Any intent, any presentation</div>
|
|
135
|
-
```
|
|
245
|
+
## Disabled controls
|
|
136
246
|
|
|
137
|
-
|
|
247
|
+
`disabled`, `aria-disabled="true"`, `data-disabled`, or `.disabled` on a control draws it at reduced opacity with a not-allowed cursor. As with buttons, only the `disabled` attribute stops input; the others change the look only.
|
|
138
248
|
|
|
139
|
-
##
|
|
249
|
+
## Building your own control
|
|
140
250
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
<input class="ipt" type="email" id="email" aria-invalid="true" aria-describedby="email-error" />
|
|
145
|
-
<span class="hint destructive" id="email-error">Enter a valid email.</span>
|
|
146
|
-
</div>
|
|
147
|
-
<label style="display: flex; gap: 0.5rem; align-items: center">
|
|
148
|
-
<input type="checkbox" class="checkbox success" />
|
|
149
|
-
<span>Accept terms</span>
|
|
150
|
-
</label>
|
|
151
|
-
<label style="display: flex; gap: 0.5rem; align-items: center">
|
|
152
|
-
<input type="radio" class="radio secondary" name="plan" />
|
|
153
|
-
<span>Standard plan</span>
|
|
154
|
-
</label>
|
|
155
|
-
<label style="display: flex; gap: 0.5rem; align-items: center">
|
|
156
|
-
<input type="checkbox" class="switch destructive" role="switch" />
|
|
157
|
-
<span>Enable</span>
|
|
158
|
-
</label>
|
|
159
|
-
```
|
|
251
|
+
For a text-like control the package does not ship, `.text-control` gives an element the same border, placeholder, hover, focus, invalid, and disabled styles as `.ipt`, without its height or padding. [Customizing → Composition helpers](./customizing.md#composition-helpers) explains it with the other building blocks.
|
|
252
|
+
|
|
253
|
+
## Next
|
|
160
254
|
|
|
161
|
-
|
|
255
|
+
The form can be filled in and submitted. [Feedback](./feedback.md) shows what the screen does next: a Save button that says it is saving, a success message, a plan badge, and a storage usage bar.
|
package/docs/usage/index.md
CHANGED
|
@@ -1,24 +1,32 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Overview
|
|
3
|
-
description:
|
|
3
|
+
description: The guides that finish the settings screen, then the lookup pages for every class, token, and default.
|
|
4
4
|
group: Usage
|
|
5
|
-
order:
|
|
5
|
+
order: 4
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Usage
|
|
9
9
|
|
|
10
|
-
These guides
|
|
10
|
+
These guides finish the settings screen started in [Building a screen](../concepts.md). Read the first seven in order: each one adds a part of the screen and assumes the ones before it. The next three are lookup pages; you will be sent to them when a guide needs the full table, and you can come back whenever you need a default or a rule. The last page, Presets, is for when the screen works and you are tired of typing the same classes.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
- [Theming](./theming.md): The color, intent, and foundation token reference.
|
|
14
|
-
- [Customizing](./customizing.md): The presentation and material token reference, aesthetic knobs, and defining a custom intent.
|
|
15
|
-
- [Aesthetics](./aesthetics.md): Each shipped aesthetic in depth, including its documented exceptions.
|
|
16
|
-
- [Buttons](./buttons.md)
|
|
17
|
-
- [Forms](./forms.md)
|
|
18
|
-
- [Feedback](./feedback.md)
|
|
19
|
-
- [Tooltips](./tooltips.md)
|
|
20
|
-
- [Content and layout](./content-and-layout.md): Layout helpers, tables, quotes, code, surfaces, and typography utilities.
|
|
12
|
+
Guides, in order:
|
|
21
13
|
|
|
22
|
-
|
|
14
|
+
1. [Buttons](./buttons.md): the danger zone's destructive action, icon buttons, sizes, link buttons, and disabled states, plus how to load icons.
|
|
15
|
+
2. [Forms](./forms.md): the profile form, with labels, hints, validation errors, an input with an icon or a fixed prefix, a select, and checkbox, radio, and switch toggles.
|
|
16
|
+
3. [Feedback](./feedback.md): what the screen shows while saving and after: a loading button, a success alert, a plan badge, a loading placeholder, and a storage usage bar.
|
|
17
|
+
4. [Tooltips](./tooltips.md): help text beside a form field, how to wire it for keyboard and screen reader users, and where a tooltip can be cut off.
|
|
18
|
+
5. [Theming](./theming.md): light and dark mode, replacing the palette with brand colors, and defining an intent of your own, with the full color and foundation token tables.
|
|
19
|
+
6. [Aesthetics](./aesthetics.md): the six optional looks, what each one changes, and its limits.
|
|
20
|
+
7. [Solo classes](./solo.md): painting an aesthetic onto a component from another library.
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
Lookup pages:
|
|
23
|
+
|
|
24
|
+
- [Composing](./composing.md): the complete rules for combining intent, presentation, and elevation, every component's defaults, and which axes each component reads.
|
|
25
|
+
- [Customizing](./customizing.md): presentation and material tokens, aesthetic knobs, the six public component variables, the generated palette, and the composition helpers for building your own components.
|
|
26
|
+
- [Content and layout](./content-and-layout.md): every layout helper, the type scale, cards and panels, tables, quotes, code, and keyboard keys.
|
|
27
|
+
|
|
28
|
+
Once the screen works:
|
|
29
|
+
|
|
30
|
+
- [Presets](./presets.md): set a look once, with axis classes on a container, theme and material tokens, or your own component classes built with `@apply`.
|
|
31
|
+
|
|
32
|
+
When you finish, [Accessibility](../accessibility.md) collects what the CSS does for you and what your application still owes its users.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Presets
|
|
3
|
+
description: Three ways to set a look once instead of on every element, and when to reach for each.
|
|
4
|
+
order: 11
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Presets
|
|
8
|
+
|
|
9
|
+
By now the settings screen says `btn primary soft sm` in a dozen places, and changing your mind means changing a dozen places. This page covers the three ways to set a look once: axis classes on a container, theme and material tokens, and your own component classes built with `@apply`. Each fits a different kind of "once".
|
|
10
|
+
|
|
11
|
+
## Which one to use
|
|
12
|
+
|
|
13
|
+
| You want | Reach for |
|
|
14
|
+
| --------------------------------------------------------------------- | ----------------------------------------------------------- |
|
|
15
|
+
| Every component in one region to share a fill, an edge, or a material | [Axis classes on a container](#axis-classes-on-a-container) |
|
|
16
|
+
| Different colors, corners, borders, or depth for a page or a region | [Theme and material tokens](#theme-and-material-tokens) |
|
|
17
|
+
| One name for a recipe you repeat, such as "the save button" | [Your own component classes](#your-own-component-classes) |
|
|
18
|
+
|
|
19
|
+
They combine. A region can set a material token, sit under an aesthetic, and hold your own button class, and each element can still override what it inherits.
|
|
20
|
+
|
|
21
|
+
## Axis classes on a container
|
|
22
|
+
|
|
23
|
+
Some classes work on a container as well as on a component, and everything inside takes them:
|
|
24
|
+
|
|
25
|
+
- The presentation classes: `.solid`, `.soft`, `.ghost`, `.edged`, and `.edgeless`.
|
|
26
|
+
- The corner patterns: `.cut-diagonal` and `.cut-diagonal-reverse`.
|
|
27
|
+
- The [aesthetics](./aesthetics.md), such as `.glass` or `.pixel`.
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<div class="cluster soft edged">
|
|
31
|
+
<button class="btn primary" type="button">Bold</button>
|
|
32
|
+
<button class="btn" type="button">Italic</button>
|
|
33
|
+
<button class="btn destructive solid" type="button">Clear formatting</button>
|
|
34
|
+
</div>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The toolbar's buttons are soft and edged, and the last one asks for its own fill. A class on the element always beats one from a container.
|
|
38
|
+
|
|
39
|
+
The other axes do not pass down. Intent, elevation (`.flat`, `.raised`, `.floating`), and size (`.sm`, `.lg`) change only the element they are on, so a `.sm` toolbar does not shrink its buttons; [Composing → Combining classes](./composing.md#combining-classes) explains why. An aesthetic class also sets its own corner pattern on its region, so a `.cut-diagonal` above a `.pixel` region does not reach inside it.
|
|
40
|
+
|
|
41
|
+
Use a container class when the look belongs to the region, such as a quiet sidebar, rather than to the components in it.
|
|
42
|
+
|
|
43
|
+
## Theme and material tokens
|
|
44
|
+
|
|
45
|
+
Tokens are CSS custom properties. Set one on `:root` and the whole page follows; set it on an element and only what is inside follows. They reach further than classes, because components read them while they draw:
|
|
46
|
+
|
|
47
|
+
```css
|
|
48
|
+
.admin {
|
|
49
|
+
--radius-control: 0.25rem;
|
|
50
|
+
--radius-surface: 0.5rem;
|
|
51
|
+
--border-width: 2px;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Every button, field, tooltip bubble, and surface inside `.admin` takes the tighter corners and the heavier border, with no class on any of them. Checkboxes, `.kbd`, and `.code` keep their own smaller corner, `--radius-small`.
|
|
56
|
+
|
|
57
|
+
The tables live where the tokens are explained, so this page does not repeat them:
|
|
58
|
+
|
|
59
|
+
- [Theming → Color tokens](./theming.md#color-tokens): brand and status colors, in both themes.
|
|
60
|
+
- [Theming → Foundation tokens](./theming.md#foundation-tokens): corners, border width, control height, focus ring, depth, and motion.
|
|
61
|
+
- [Customizing → Presentation tokens](./customizing.md#presentation-tokens): how much a fill, an edge, or a hover gives.
|
|
62
|
+
- [Customizing → Material tokens](./customizing.md#material-tokens): what an aesthetic sets, which you can set yourself, such as `--ui-radius`.
|
|
63
|
+
- [Customizing → Aesthetic tokens](./customizing.md#aesthetic-tokens): the knobs of each aesthetic, such as `--neo-offset`.
|
|
64
|
+
|
|
65
|
+
Use tokens when the change is a value, such as a color or a corner, rather than a choice between classes.
|
|
66
|
+
|
|
67
|
+
## Your own component classes
|
|
68
|
+
|
|
69
|
+
With the Tailwind source entrypoints, every component, helper, and axis class is a Tailwind utility, so one class of yours can carry the whole recipe:
|
|
70
|
+
|
|
71
|
+
```css
|
|
72
|
+
@import "@codenhub/styles/tw";
|
|
73
|
+
|
|
74
|
+
@utility btn-save {
|
|
75
|
+
@apply btn primary soft sm;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```html
|
|
80
|
+
<button class="btn-save" type="submit">Save changes</button>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`btn-save` behaves like `btn primary soft sm` written out, aesthetics and hover included, and changing the recipe changes every save button. Modifiers that belong to one component, such as `.tight` on `.stack` or `.icon` on `.btn`, are utilities too, so `@apply btn icon` gives you an icon button of your own. [Tailwind CSS v4 → Build your own components with `@apply`](../integrating/tailwind.md#build-your-own-components-with-apply) has the rules, including why `@utility` beats a plain rule.
|
|
84
|
+
|
|
85
|
+
With the compiled CSS there is no `@apply`. Keep the recipe in one place on the other side instead: a template partial, a component in your framework, or a constant such as `const saveButton = "btn primary soft sm"`.
|
|
86
|
+
|
|
87
|
+
Use your own class when the same combination names one thing in your design, such as the save button or the plan card.
|
|
88
|
+
|
|
89
|
+
## Next
|
|
90
|
+
|
|
91
|
+
[Accessibility](../accessibility.md) lists what the CSS does for your users and what your application still owes them.
|