@tempoxyz/ds 0.3.10 → 0.3.11
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/dist/docs/AGENTS.md +9 -0
- package/dist/docs/components/accordion.md +489 -0
- package/dist/docs/components/address-card.md +147 -0
- package/dist/docs/components/agent-logo.md +194 -0
- package/dist/docs/components/alert-dialog.md +631 -0
- package/dist/docs/components/alert.md +448 -0
- package/dist/docs/components/amount-input.md +305 -0
- package/dist/docs/components/amount.md +794 -0
- package/dist/docs/components/app-shell.md +559 -0
- package/dist/docs/components/asset-chip.md +294 -0
- package/dist/docs/components/autocomplete.md +619 -0
- package/dist/docs/components/avatar.md +321 -0
- package/dist/docs/components/badge.md +339 -0
- package/dist/docs/components/badged-logo.md +116 -0
- package/dist/docs/components/banner.md +379 -0
- package/dist/docs/components/bar-chart.md +208 -0
- package/dist/docs/components/breadcrumbs.md +380 -0
- package/dist/docs/components/button-group.md +286 -0
- package/dist/docs/components/button.md +650 -0
- package/dist/docs/components/calendar.md +375 -0
- package/dist/docs/components/callout.md +96 -0
- package/dist/docs/components/checkbox-group.md +521 -0
- package/dist/docs/components/checkbox.md +467 -0
- package/dist/docs/components/choice-group.md +516 -0
- package/dist/docs/components/choicebox.md +641 -0
- package/dist/docs/components/code.md +100 -0
- package/dist/docs/components/combobox.md +939 -0
- package/dist/docs/components/container.md +257 -0
- package/dist/docs/components/copy-button.md +642 -0
- package/dist/docs/components/date-picker.md +514 -0
- package/dist/docs/components/dialog.md +1332 -0
- package/dist/docs/components/drawer.md +966 -0
- package/dist/docs/components/empty.md +340 -0
- package/dist/docs/components/field.md +570 -0
- package/dist/docs/components/fieldset.md +398 -0
- package/dist/docs/components/frame.md +434 -0
- package/dist/docs/components/gauge.md +299 -0
- package/dist/docs/components/get-started-visual.md +117 -0
- package/dist/docs/components/grid.md +288 -0
- package/dist/docs/components/hero-visual.md +155 -0
- package/dist/docs/components/hex.md +487 -0
- package/dist/docs/components/icon-tile.md +292 -0
- package/dist/docs/components/identicon.md +371 -0
- package/dist/docs/components/inline.md +233 -0
- package/dist/docs/components/inset.md +225 -0
- package/dist/docs/components/kbd.md +423 -0
- package/dist/docs/components/list-group.md +981 -0
- package/dist/docs/components/loading-dots.md +237 -0
- package/dist/docs/components/menu.md +934 -0
- package/dist/docs/components/native-select.md +204 -0
- package/dist/docs/components/network-logo.md +248 -0
- package/dist/docs/components/number-field.md +543 -0
- package/dist/docs/components/otp-field.md +616 -0
- package/dist/docs/components/pagination.md +516 -0
- package/dist/docs/components/popover.md +544 -0
- package/dist/docs/components/progress.md +388 -0
- package/dist/docs/components/qr.md +314 -0
- package/dist/docs/components/radio-group.md +528 -0
- package/dist/docs/components/secret-value.md +406 -0
- package/dist/docs/components/select.md +751 -0
- package/dist/docs/components/separator.md +379 -0
- package/dist/docs/components/sidebar-menu.md +922 -0
- package/dist/docs/components/skeleton.md +517 -0
- package/dist/docs/components/slider.md +539 -0
- package/dist/docs/components/snippet.md +424 -0
- package/dist/docs/components/spinner.md +216 -0
- package/dist/docs/components/split-bar.md +139 -0
- package/dist/docs/components/split-button.md +464 -0
- package/dist/docs/components/stack.md +299 -0
- package/dist/docs/components/status-chip.md +226 -0
- package/dist/docs/components/status-indicator.md +119 -0
- package/dist/docs/components/status-row.md +174 -0
- package/dist/docs/components/stepper.md +451 -0
- package/dist/docs/components/success-hero.md +157 -0
- package/dist/docs/components/surface.md +639 -0
- package/dist/docs/components/switch.md +472 -0
- package/dist/docs/components/table.md +967 -0
- package/dist/docs/components/tabs.md +627 -0
- package/dist/docs/components/tempo-logo.md +185 -0
- package/dist/docs/components/text-input.md +624 -0
- package/dist/docs/components/textarea.md +352 -0
- package/dist/docs/components/toast.md +535 -0
- package/dist/docs/components/token-logo.md +371 -0
- package/dist/docs/components/token.md +247 -0
- package/dist/docs/components/tooltip.md +490 -0
- package/dist/docs/components/verification-code.md +116 -0
- package/dist/docs/components/visual.md +249 -0
- package/dist/docs/components.md +203 -0
- package/dist/docs/foundations/accessibility.md +377 -0
- package/dist/docs/foundations/agents.md +150 -0
- package/dist/docs/foundations/color.md +522 -0
- package/dist/docs/foundations/content/tone.md +194 -0
- package/dist/docs/foundations/content/voice.md +194 -0
- package/dist/docs/foundations/content/writing-style.md +406 -0
- package/dist/docs/foundations/iconography.md +282 -0
- package/dist/docs/foundations/intent.md +360 -0
- package/dist/docs/foundations/layout.md +508 -0
- package/dist/docs/foundations/linter.md +296 -0
- package/dist/docs/foundations/motion.md +151 -0
- package/dist/docs/foundations/radius-and-padding.md +86 -0
- package/dist/docs/foundations/typography.md +266 -0
- package/dist/docs/index.md +137 -0
- package/dist/docs/introduction/faq.md +132 -0
- package/dist/docs/introduction/getting-started.md +377 -0
- package/dist/docs/patterns/blockchain-values.md +709 -0
- package/dist/docs/patterns/dashboards.md +638 -0
- package/dist/docs/patterns/destructive-actions.md +626 -0
- package/dist/docs/patterns/empty-states.md +612 -0
- package/dist/docs/patterns/errors-and-validation.md +808 -0
- package/dist/docs/patterns/feedback-and-status.md +518 -0
- package/dist/docs/patterns/forms.md +679 -0
- package/dist/docs/patterns/loading.md +630 -0
- package/dist/docs/patterns/navigation.md +397 -0
- package/dist/docs/patterns/payments.md +765 -0
- package/dist/docs/patterns/responsive-layout.md +997 -0
- package/dist/docs/patterns/tables-and-lists.md +964 -0
- package/dist/docs/products/tempo-console.md +671 -0
- package/dist/docs/products/tempo-performance.md +437 -0
- package/dist/docs/products/tempo-wallet.md +438 -0
- package/package.json +1 -1
|
@@ -0,0 +1,650 @@
|
|
|
1
|
+
# Button
|
|
2
|
+
|
|
3
|
+
Triggers an action, such as submitting a form or sending a payment.
|
|
4
|
+
|
|
5
|
+
[View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/Button.tsx)
|
|
6
|
+
|
|
7
|
+
Figma: [Button](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=1186-3148), [Icon Button](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=1186-3395), [Text Button](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=5601-90)
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
A native `<button>` for actions. `Button.Link` renders the same styles for navigation.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### Basic
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Button } from '@tempoxyz/ds'
|
|
19
|
+
|
|
20
|
+
export function Demo() {
|
|
21
|
+
return <Button>Continue</Button>
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Button/Basic.tsx)
|
|
26
|
+
|
|
27
|
+
### Variant
|
|
28
|
+
|
|
29
|
+
Set `variant` to `primary` (default), `secondary`, `tertiary`, `danger`, or `text`. A `tertiary` button has no fill until hover.
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { Button, style } from '@tempoxyz/ds'
|
|
33
|
+
|
|
34
|
+
export function Demo() {
|
|
35
|
+
return (
|
|
36
|
+
<div {...styles.row()}>
|
|
37
|
+
{(['primary', 'secondary', 'tertiary', 'danger'] as const).map((variant) => (
|
|
38
|
+
<Button key={variant} variant={variant}>
|
|
39
|
+
Continue
|
|
40
|
+
</Button>
|
|
41
|
+
))}
|
|
42
|
+
</div>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
namespace styles {
|
|
47
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Button/Variant.tsx)
|
|
52
|
+
|
|
53
|
+
### Text
|
|
54
|
+
|
|
55
|
+
Set `variant="text"` for a low-emphasis action in running content, such as See more. It renders the secondary label and a trailing 12px icon without a fill or padding, and ignores `size`.
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { Button } from '@tempoxyz/ds'
|
|
59
|
+
import { ChevronRight } from '@tempoxyz/ds/icons'
|
|
60
|
+
|
|
61
|
+
export function Demo() {
|
|
62
|
+
return (
|
|
63
|
+
<Button variant="text">
|
|
64
|
+
See more
|
|
65
|
+
<ChevronRight />
|
|
66
|
+
</Button>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Button/Text.tsx)
|
|
72
|
+
|
|
73
|
+
### Inverse
|
|
74
|
+
|
|
75
|
+
Set `appearance="inverse"` on an inverse surface, such as a dark banner on a light page. The surface turns light in dark mode, and the button colors flip with it.
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
/** Demonstrates the inverse appearance of each Button variant on an inverse surface. @module */
|
|
79
|
+
import { Button, style } from '@tempoxyz/ds'
|
|
80
|
+
|
|
81
|
+
export function Demo() {
|
|
82
|
+
return (
|
|
83
|
+
<div {...styles.surface()}>
|
|
84
|
+
{(['primary', 'secondary', 'tertiary'] as const).map((variant) => (
|
|
85
|
+
<Button appearance="inverse" key={variant} variant={variant}>
|
|
86
|
+
Continue
|
|
87
|
+
</Button>
|
|
88
|
+
))}
|
|
89
|
+
</div>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
namespace styles {
|
|
94
|
+
export const surface = style({
|
|
95
|
+
alignItems: 'center',
|
|
96
|
+
backgroundColor: 'inverse.background.primary',
|
|
97
|
+
borderRadius: 'sm',
|
|
98
|
+
display: 'flex',
|
|
99
|
+
flexWrap: 'wrap',
|
|
100
|
+
gap: '12',
|
|
101
|
+
padding: '16',
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Button/Inverse.tsx)
|
|
107
|
+
|
|
108
|
+
### Overlay
|
|
109
|
+
|
|
110
|
+
Set `appearance="overlay"` over an image or video. The `secondary` fill is a translucent gray, and the `secondary` and `tertiary` labels stay white in both color schemes.
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
/** Demonstrates the overlay appearance of each Button variant over an image. @module */
|
|
114
|
+
import { Button, style } from '@tempoxyz/ds'
|
|
115
|
+
|
|
116
|
+
export function Demo() {
|
|
117
|
+
return (
|
|
118
|
+
<div {...styles.image()}>
|
|
119
|
+
{(['primary', 'secondary', 'tertiary'] as const).map((variant) => (
|
|
120
|
+
<Button appearance="overlay" key={variant} variant={variant}>
|
|
121
|
+
Continue
|
|
122
|
+
</Button>
|
|
123
|
+
))}
|
|
124
|
+
</div>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
namespace styles {
|
|
129
|
+
// A mid-tone gradient stands in for a photo, so the labels stay legible in both color schemes.
|
|
130
|
+
export const image = style({
|
|
131
|
+
alignItems: 'center',
|
|
132
|
+
backgroundImage: 'linear-gradient(135deg, #6b7f99, #a3866a) !custom',
|
|
133
|
+
borderRadius: 'sm',
|
|
134
|
+
display: 'flex',
|
|
135
|
+
flexWrap: 'wrap',
|
|
136
|
+
gap: '12',
|
|
137
|
+
padding: '16',
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Button/Overlay.tsx)
|
|
143
|
+
|
|
144
|
+
### Size
|
|
145
|
+
|
|
146
|
+
Set `size` to `xsmall`, `small`, `medium` (default), or `large`. Heights step from 24px to 48px. `large` and `medium` take the `sm` corner radius, `small` takes `xs`, and `xsmall` renders a pill.
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
import { Button, style } from '@tempoxyz/ds'
|
|
150
|
+
|
|
151
|
+
export function Demo() {
|
|
152
|
+
return (
|
|
153
|
+
<div {...styles.row()}>
|
|
154
|
+
{(['xsmall', 'small', 'medium', 'large'] as const).map((size) => (
|
|
155
|
+
<Button key={size} size={size}>
|
|
156
|
+
Continue
|
|
157
|
+
</Button>
|
|
158
|
+
))}
|
|
159
|
+
</div>
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
namespace styles {
|
|
164
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Button/Size.tsx)
|
|
169
|
+
|
|
170
|
+
### Shape
|
|
171
|
+
|
|
172
|
+
Set `shape="icon"` for a round button that holds only an icon. The icon renders at 16px, and at 20px on a large button. Give the button an `aria-label`.
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
import { Button, style } from '@tempoxyz/ds'
|
|
176
|
+
import { Plus as Add } from '@tempoxyz/ds/icons'
|
|
177
|
+
|
|
178
|
+
export function Demo() {
|
|
179
|
+
return (
|
|
180
|
+
<div {...styles.row()}>
|
|
181
|
+
<Button>
|
|
182
|
+
<Add />
|
|
183
|
+
Add funds
|
|
184
|
+
</Button>
|
|
185
|
+
{(['primary', 'secondary', 'tertiary'] as const).map((variant) => (
|
|
186
|
+
<Button aria-label="Add" key={variant} shape="icon" variant={variant}>
|
|
187
|
+
<Add />
|
|
188
|
+
</Button>
|
|
189
|
+
))}
|
|
190
|
+
</div>
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
namespace styles {
|
|
195
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Button/Shape.tsx)
|
|
200
|
+
|
|
201
|
+
### Loading
|
|
202
|
+
|
|
203
|
+
Set `loading` to disable the button and show a spinner before its label.
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
import { Button, style } from '@tempoxyz/ds'
|
|
207
|
+
|
|
208
|
+
export function Demo() {
|
|
209
|
+
return (
|
|
210
|
+
<div {...styles.row()}>
|
|
211
|
+
{(['primary', 'secondary', 'tertiary'] as const).map((variant) => (
|
|
212
|
+
<Button key={variant} loading variant={variant}>
|
|
213
|
+
Loading
|
|
214
|
+
</Button>
|
|
215
|
+
))}
|
|
216
|
+
</div>
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
namespace styles {
|
|
221
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Button/Loading.tsx)
|
|
226
|
+
|
|
227
|
+
### Disabled
|
|
228
|
+
|
|
229
|
+
```tsx
|
|
230
|
+
import { Button, style } from '@tempoxyz/ds'
|
|
231
|
+
|
|
232
|
+
export function Demo() {
|
|
233
|
+
return (
|
|
234
|
+
<div {...styles.row()}>
|
|
235
|
+
{(['primary', 'secondary', 'tertiary'] as const).map((variant) => (
|
|
236
|
+
<Button disabled key={variant} variant={variant}>
|
|
237
|
+
Disabled
|
|
238
|
+
</Button>
|
|
239
|
+
))}
|
|
240
|
+
</div>
|
|
241
|
+
)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
namespace styles {
|
|
245
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Button/Disabled.tsx)
|
|
250
|
+
|
|
251
|
+
## Anatomy
|
|
252
|
+
|
|
253
|
+
Import the component and assemble its parts.
|
|
254
|
+
|
|
255
|
+
```tsx
|
|
256
|
+
import { Button } from '@tempoxyz/ds'
|
|
257
|
+
|
|
258
|
+
<Button />
|
|
259
|
+
<Button.Link />
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Guidelines
|
|
263
|
+
|
|
264
|
+
### When to Use
|
|
265
|
+
|
|
266
|
+
* Start an action in the current view, such as Send payment, Save changes, or Open settings.
|
|
267
|
+
* Submit a form. Set `type="submit"` on the form's main button.
|
|
268
|
+
* Use `Button.Link` when navigation needs a button's weight, such as Create account in an empty state.
|
|
269
|
+
|
|
270
|
+
### When Not to Use
|
|
271
|
+
|
|
272
|
+
* Use a text link for navigation inside sentences, lists, and tables.
|
|
273
|
+
* Use [CopyButton](/docs/components/copy-button) to copy a value, and [SplitButton](/docs/components/split-button) for a main action with related alternatives.
|
|
274
|
+
* Use [Tabs](/docs/components/tabs) or [ChoiceGroup](/docs/components/choice-group) to switch views, and [Switch](/docs/components/switch) to turn a setting on or off.
|
|
275
|
+
* If a section has more than three secondary actions, put them in a [Menu](/docs/components/menu) behind an icon button.
|
|
276
|
+
|
|
277
|
+
### Choose a Variant by Emphasis
|
|
278
|
+
|
|
279
|
+
* **Main Action (primary):** The main action of a view, dialog, or section, such as Send payment. Use one per section.
|
|
280
|
+
* **Supporting Actions (secondary):** Supporting actions beside a primary action, or actions of equal weight.
|
|
281
|
+
* **Low-Emphasis Actions (tertiary):** Dense areas, such as toolbars, table rows, and inline Cancel actions.
|
|
282
|
+
|
|
283
|
+
A destructive action takes the variant of its place in the flow, and its label names the outcome, such as Revoke key. Confirm it with an [AlertDialog](/docs/components/alert-dialog), whose confirming button takes `danger`. See [Destructive Actions](/docs/patterns/destructive-actions) and [Payments](/docs/patterns/payments).
|
|
284
|
+
|
|
285
|
+
### Use One Primary Action
|
|
286
|
+
|
|
287
|
+
Give other actions `secondary` or `tertiary`, even if they matter. [Forms](/docs/patterns/forms#submitting) sets the order of the actions.
|
|
288
|
+
|
|
289
|
+
**Do:** Pair one `primary` action with `secondary` alternatives.
|
|
290
|
+
|
|
291
|
+
```tsx
|
|
292
|
+
/**
|
|
293
|
+
* Do example for "Use One Primary Action" on the Button page.
|
|
294
|
+
* Pair one `primary` action with `secondary` alternatives.
|
|
295
|
+
* @module
|
|
296
|
+
*/
|
|
297
|
+
import { Button, style } from '@tempoxyz/ds'
|
|
298
|
+
|
|
299
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
300
|
+
export function Demo() {
|
|
301
|
+
return (
|
|
302
|
+
<div {...styles.row()}>
|
|
303
|
+
<Button variant="secondary">Cancel</Button>
|
|
304
|
+
<Button>Send payment</Button>
|
|
305
|
+
</div>
|
|
306
|
+
)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
namespace styles {
|
|
310
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**Don't:** Give several actions in one section the `primary` variant.
|
|
315
|
+
|
|
316
|
+
```tsx
|
|
317
|
+
/**
|
|
318
|
+
* Don't example for "Use One Primary Action" on the Button page.
|
|
319
|
+
* Don't give several actions in one section the `primary` variant.
|
|
320
|
+
* @module
|
|
321
|
+
*/
|
|
322
|
+
import { Button, style } from '@tempoxyz/ds'
|
|
323
|
+
|
|
324
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
325
|
+
export function Demo() {
|
|
326
|
+
return (
|
|
327
|
+
<div {...styles.row()}>
|
|
328
|
+
<Button>Send</Button>
|
|
329
|
+
<Button>Deposit</Button>
|
|
330
|
+
<Button>Swap</Button>
|
|
331
|
+
</div>
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
namespace styles {
|
|
336
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Match Size to Context
|
|
341
|
+
|
|
342
|
+
* **Row Actions (xsmall):** A pill for an action inside a row or field, such as Copy or Edit. Never the main action.
|
|
343
|
+
* **Dense Layouts (small):** Tables, toolbars, cards, and icon buttons inside fields and rows, such as Export in a toolbar.
|
|
344
|
+
* **Default (medium):** Forms, page actions, and actions inside a dialog body, such as Copy address.
|
|
345
|
+
* **Dialog Footers (large):** Every action in a dialog footer, and the final step of a focused flow, such as Confirm send.
|
|
346
|
+
|
|
347
|
+
Lay out the actions in a dialog footer with a [ButtonGroup](/docs/components/button-group).
|
|
348
|
+
|
|
349
|
+
### Show Progress With Loading
|
|
350
|
+
|
|
351
|
+
**Do:** Set `loading` on the button that started the action.
|
|
352
|
+
|
|
353
|
+
```tsx
|
|
354
|
+
/**
|
|
355
|
+
* Do example for "Show Progress With Loading" on the Button page.
|
|
356
|
+
* Set `loading` on the button that started the action.
|
|
357
|
+
* @module
|
|
358
|
+
*/
|
|
359
|
+
import { Button } from '@tempoxyz/ds'
|
|
360
|
+
|
|
361
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
362
|
+
export function Demo() {
|
|
363
|
+
return <Button loading>Send payment</Button>
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**Don't:** Disable the button and place a separate [Spinner](/docs/components/spinner) beside it.
|
|
368
|
+
|
|
369
|
+
```tsx
|
|
370
|
+
/**
|
|
371
|
+
* Don't example for "Show Progress With Loading" on the Button page.
|
|
372
|
+
* Don't disable the button and place a separate Spinner beside it.
|
|
373
|
+
* @module
|
|
374
|
+
*/
|
|
375
|
+
import { Button, Spinner, style } from '@tempoxyz/ds'
|
|
376
|
+
|
|
377
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
378
|
+
export function Demo() {
|
|
379
|
+
return (
|
|
380
|
+
<div {...styles.row()}>
|
|
381
|
+
<Button disabled>Send payment</Button>
|
|
382
|
+
<Spinner aria-label="Loading" />
|
|
383
|
+
</div>
|
|
384
|
+
)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
namespace styles {
|
|
388
|
+
export const row = style({ alignItems: 'center', display: 'flex', gap: '12' })
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Avoid Disabled Buttons
|
|
393
|
+
|
|
394
|
+
Keep a button enabled when you can, and show validation errors after a press. If a button must stay disabled:
|
|
395
|
+
|
|
396
|
+
* Explain why in nearby text.
|
|
397
|
+
* Set `focusableWhenDisabled` so keyboard users can reach it.
|
|
398
|
+
* Don't rely on a [Tooltip](/docs/components/tooltip). Many readers can't open it on a disabled button.
|
|
399
|
+
|
|
400
|
+
**Do:** Explain in nearby text why the button is unavailable.
|
|
401
|
+
|
|
402
|
+
```tsx
|
|
403
|
+
/**
|
|
404
|
+
* Do example for "Avoid Disabled Buttons" on the Button page.
|
|
405
|
+
* Explain in nearby text why the button is unavailable.
|
|
406
|
+
* @module
|
|
407
|
+
*/
|
|
408
|
+
import { Button, style } from '@tempoxyz/ds'
|
|
409
|
+
|
|
410
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
411
|
+
export function Demo() {
|
|
412
|
+
return (
|
|
413
|
+
<div {...styles.stack()}>
|
|
414
|
+
<Button disabled focusableWhenDisabled>
|
|
415
|
+
Send payment
|
|
416
|
+
</Button>
|
|
417
|
+
<p {...styles.hint()}>Add a recipient address to send.</p>
|
|
418
|
+
</div>
|
|
419
|
+
)
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
namespace styles {
|
|
423
|
+
export const hint = style({
|
|
424
|
+
color: 'content.secondary',
|
|
425
|
+
margin: '0 !custom',
|
|
426
|
+
typography: 'body.b3',
|
|
427
|
+
})
|
|
428
|
+
|
|
429
|
+
export const stack = style({
|
|
430
|
+
alignItems: 'flex-start',
|
|
431
|
+
display: 'flex',
|
|
432
|
+
flexDirection: 'column',
|
|
433
|
+
rowGap: '8',
|
|
434
|
+
})
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
**Don't:** Disable a button without saying what is missing.
|
|
439
|
+
|
|
440
|
+
```tsx
|
|
441
|
+
/**
|
|
442
|
+
* Don't example for "Avoid Disabled Buttons" on the Button page.
|
|
443
|
+
* Don't disable a button without saying what is missing.
|
|
444
|
+
* @module
|
|
445
|
+
*/
|
|
446
|
+
import { Button, style } from '@tempoxyz/ds'
|
|
447
|
+
|
|
448
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
449
|
+
export function Demo() {
|
|
450
|
+
return (
|
|
451
|
+
<div {...styles.stack()}>
|
|
452
|
+
<Button disabled>Send payment</Button>
|
|
453
|
+
</div>
|
|
454
|
+
)
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
namespace styles {
|
|
458
|
+
export const stack = style({
|
|
459
|
+
alignItems: 'flex-start',
|
|
460
|
+
display: 'flex',
|
|
461
|
+
flexDirection: 'column',
|
|
462
|
+
rowGap: '8',
|
|
463
|
+
})
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### Use Icons to Reinforce the Label
|
|
468
|
+
|
|
469
|
+
Place an icon before the label if it aids recognition, such as a plus for Add. An icon-only button (`shape="icon"`) needs a [Tooltip](/docs/components/tooltip) with its `aria-label` text. Use it only for familiar actions, such as Close or Copy.
|
|
470
|
+
|
|
471
|
+
**Do:** Add an icon only where it aids recognition.
|
|
472
|
+
|
|
473
|
+
```tsx
|
|
474
|
+
/**
|
|
475
|
+
* Do example for "Use Icons to Reinforce the Label" on the Button page.
|
|
476
|
+
* Add an icon only where it aids recognition.
|
|
477
|
+
* @module
|
|
478
|
+
*/
|
|
479
|
+
import { Button, style } from '@tempoxyz/ds'
|
|
480
|
+
import { Plus } from '@tempoxyz/ds/icons'
|
|
481
|
+
|
|
482
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
483
|
+
export function Demo() {
|
|
484
|
+
return (
|
|
485
|
+
<div {...styles.row()}>
|
|
486
|
+
<Button size="small" variant="secondary">
|
|
487
|
+
Export
|
|
488
|
+
</Button>
|
|
489
|
+
<Button size="small" variant="secondary">
|
|
490
|
+
Rotate key
|
|
491
|
+
</Button>
|
|
492
|
+
<Button size="small">
|
|
493
|
+
<Plus />
|
|
494
|
+
Add key
|
|
495
|
+
</Button>
|
|
496
|
+
</div>
|
|
497
|
+
)
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
namespace styles {
|
|
501
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '8' })
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
**Don't:** Add icons to every button in a group.
|
|
506
|
+
|
|
507
|
+
```tsx
|
|
508
|
+
/**
|
|
509
|
+
* Don't example for "Use Icons to Reinforce the Label" on the Button page.
|
|
510
|
+
* Don't add icons to every button in a group.
|
|
511
|
+
* @module
|
|
512
|
+
*/
|
|
513
|
+
import { Button, style } from '@tempoxyz/ds'
|
|
514
|
+
import { Export, Plus, Refresh } from '@tempoxyz/ds/icons'
|
|
515
|
+
|
|
516
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
517
|
+
export function Demo() {
|
|
518
|
+
return (
|
|
519
|
+
<div {...styles.row()}>
|
|
520
|
+
<Button size="small" variant="secondary">
|
|
521
|
+
<Export />
|
|
522
|
+
Export
|
|
523
|
+
</Button>
|
|
524
|
+
<Button size="small" variant="secondary">
|
|
525
|
+
<Refresh />
|
|
526
|
+
Rotate key
|
|
527
|
+
</Button>
|
|
528
|
+
<Button size="small">
|
|
529
|
+
<Plus />
|
|
530
|
+
Add key
|
|
531
|
+
</Button>
|
|
532
|
+
</div>
|
|
533
|
+
)
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
namespace styles {
|
|
537
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '8' })
|
|
538
|
+
}
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
## Content
|
|
542
|
+
|
|
543
|
+
### Start With a Verb
|
|
544
|
+
|
|
545
|
+
Name the action and its object, such as Send payment or Create key.
|
|
546
|
+
|
|
547
|
+
**Do:** Repeat the action on each button, such as Revoke key and Keep key.
|
|
548
|
+
|
|
549
|
+
```tsx
|
|
550
|
+
/**
|
|
551
|
+
* Do example for "Start With a Verb" on the Button page.
|
|
552
|
+
* Repeat the action on each button, such as Revoke key and Keep key.
|
|
553
|
+
* @module
|
|
554
|
+
*/
|
|
555
|
+
import { Button, style } from '@tempoxyz/ds'
|
|
556
|
+
|
|
557
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
558
|
+
export function Demo() {
|
|
559
|
+
return (
|
|
560
|
+
<div {...styles.row()}>
|
|
561
|
+
<Button variant="secondary">Keep key</Button>
|
|
562
|
+
<Button>Revoke key</Button>
|
|
563
|
+
</div>
|
|
564
|
+
)
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
namespace styles {
|
|
568
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
**Don't:** Use generic labels such as Yes, No, OK, or Submit.
|
|
573
|
+
|
|
574
|
+
```tsx
|
|
575
|
+
/**
|
|
576
|
+
* Don't example for "Start With a Verb" on the Button page.
|
|
577
|
+
* Don't use generic labels such as Yes, No, OK, or Submit.
|
|
578
|
+
* @module
|
|
579
|
+
*/
|
|
580
|
+
import { Button, style } from '@tempoxyz/ds'
|
|
581
|
+
|
|
582
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
583
|
+
export function Demo() {
|
|
584
|
+
return (
|
|
585
|
+
<div {...styles.row()}>
|
|
586
|
+
<Button variant="secondary">No</Button>
|
|
587
|
+
<Button>Yes</Button>
|
|
588
|
+
</div>
|
|
589
|
+
)
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
namespace styles {
|
|
593
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
|
|
594
|
+
}
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
### Describe the Outcome, Not the Control
|
|
598
|
+
|
|
599
|
+
Write Continue to review, not Click here. Screen readers list buttons out of context, so each label must make sense alone.
|
|
600
|
+
|
|
601
|
+
## Accessibility
|
|
602
|
+
|
|
603
|
+
`Button` renders a native `<button type="button">`, and `Button.Link` a native `<a>`. Both follow the [WAI-ARIA button pattern](https://www.w3.org/WAI/ARIA/apg/patterns/button/). See [Accessibility](/docs/foundations/accessibility) for the baseline.
|
|
604
|
+
|
|
605
|
+
### Semantics
|
|
606
|
+
|
|
607
|
+
* **Button (button):** Enter and Space activate it. Name an icon-only button with `aria-label`.
|
|
608
|
+
* **Button.Link (link):** Announced as a link and listed among the page's links. A modifier click opens a new tab.
|
|
609
|
+
* **Disabled:** Removes the button from the tab order, so keyboards skip it. Explain the reason in nearby text.
|
|
610
|
+
* **Focusable When Disabled (aria-disabled):** Keeps a disabled button in the tab order. It ignores every key except Tab.
|
|
611
|
+
* **Loading (aria-busy):** Disables the button and labels its spinner "Loading" for screen readers.
|
|
612
|
+
* **Icons (aria-hidden):** Hidden from assistive technology, so the button's text or label names it.
|
|
613
|
+
|
|
614
|
+
### Keyboard
|
|
615
|
+
|
|
616
|
+
* **Move to the Button (Tab):** Focuses the button, skipping disabled ones.
|
|
617
|
+
* **Activate the Button (Enter or Space):** Activates the button.
|
|
618
|
+
* **Follow a Link (Enter):** Follows a `Button.Link`.
|
|
619
|
+
|
|
620
|
+
### Your Responsibilities
|
|
621
|
+
|
|
622
|
+
* **Name Icon-Only Buttons (aria-label):** An icon-only button has no visible text. Name the action, such as "Copy address", not "Copy icon".
|
|
623
|
+
* **Announce Loading Results:** Loading announces only the busy state. Announce the outcome with a [Toast](/docs/components/toast) or an [Alert](/docs/components/alert).
|
|
624
|
+
* **Use Links for Navigation (Button.Link):** Use it for navigation, not a button with a click handler that changes the page.
|
|
625
|
+
|
|
626
|
+
## Related
|
|
627
|
+
|
|
628
|
+
[ButtonGroup](/docs/components/button-group)
|
|
629
|
+
|
|
630
|
+
Use for the actions at the foot of a dialog.
|
|
631
|
+
|
|
632
|
+
[SplitButton](/docs/components/split-button)
|
|
633
|
+
|
|
634
|
+
Use for a main action with alternatives.
|
|
635
|
+
|
|
636
|
+
[CopyButton](/docs/components/copy-button)
|
|
637
|
+
|
|
638
|
+
Use for copying a value.
|
|
639
|
+
|
|
640
|
+
[AlertDialog](/docs/components/alert-dialog)
|
|
641
|
+
|
|
642
|
+
Use for confirming an action.
|
|
643
|
+
|
|
644
|
+
[Forms](/docs/patterns/forms)
|
|
645
|
+
|
|
646
|
+
Covers placing submit and cancel actions.
|
|
647
|
+
|
|
648
|
+
[Destructive Actions](/docs/patterns/destructive-actions)
|
|
649
|
+
|
|
650
|
+
Covers deleting and revoking.
|