@tempoxyz/ds 0.3.10 → 0.3.13

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.
Files changed (210) hide show
  1. package/README.md +7 -6
  2. package/dist/docs/AGENTS.md +12 -0
  3. package/dist/docs/index.md +145 -0
  4. package/dist/docs/marketing/introduction/getting-started.md +241 -0
  5. package/dist/docs/product/components/accordion.md +489 -0
  6. package/dist/docs/product/components/address-card.md +147 -0
  7. package/dist/docs/product/components/agent-logo.md +194 -0
  8. package/dist/docs/product/components/alert-dialog.md +631 -0
  9. package/dist/docs/product/components/alert.md +448 -0
  10. package/dist/docs/product/components/amount-input.md +305 -0
  11. package/dist/docs/product/components/amount.md +794 -0
  12. package/dist/docs/product/components/app-shell.md +559 -0
  13. package/dist/docs/product/components/asset-chip.md +294 -0
  14. package/dist/docs/product/components/autocomplete.md +620 -0
  15. package/dist/docs/product/components/avatar.md +321 -0
  16. package/dist/docs/product/components/badge.md +339 -0
  17. package/dist/docs/product/components/badged-logo.md +116 -0
  18. package/dist/docs/product/components/banner.md +379 -0
  19. package/dist/docs/product/components/bar-chart.md +208 -0
  20. package/dist/docs/product/components/breadcrumbs.md +380 -0
  21. package/dist/docs/product/components/button-group.md +286 -0
  22. package/dist/docs/product/components/button.md +650 -0
  23. package/dist/docs/product/components/calendar.md +375 -0
  24. package/dist/docs/product/components/callout.md +96 -0
  25. package/dist/docs/product/components/checkbox-group.md +521 -0
  26. package/dist/docs/product/components/checkbox.md +467 -0
  27. package/dist/docs/product/components/choice-group.md +516 -0
  28. package/dist/docs/product/components/choicebox.md +641 -0
  29. package/dist/docs/product/components/code.md +100 -0
  30. package/dist/docs/product/components/combobox.md +939 -0
  31. package/dist/docs/product/components/container.md +257 -0
  32. package/dist/docs/product/components/copy-button.md +642 -0
  33. package/dist/docs/product/components/date-picker.md +514 -0
  34. package/dist/docs/product/components/dialog.md +1332 -0
  35. package/dist/docs/product/components/drawer.md +966 -0
  36. package/dist/docs/product/components/empty.md +340 -0
  37. package/dist/docs/product/components/field.md +570 -0
  38. package/dist/docs/product/components/fieldset.md +398 -0
  39. package/dist/docs/product/components/frame.md +434 -0
  40. package/dist/docs/product/components/gauge.md +299 -0
  41. package/dist/docs/product/components/get-started-visual.md +117 -0
  42. package/dist/docs/product/components/grid.md +288 -0
  43. package/dist/docs/product/components/hero-visual.md +155 -0
  44. package/dist/docs/product/components/hex.md +487 -0
  45. package/dist/docs/product/components/icon-tile.md +292 -0
  46. package/dist/docs/product/components/identicon.md +371 -0
  47. package/dist/docs/product/components/inline.md +233 -0
  48. package/dist/docs/product/components/inset.md +225 -0
  49. package/dist/docs/product/components/kbd.md +423 -0
  50. package/dist/docs/product/components/list-group.md +981 -0
  51. package/dist/docs/product/components/loading-dots.md +237 -0
  52. package/dist/docs/product/components/menu.md +934 -0
  53. package/dist/docs/product/components/native-select.md +204 -0
  54. package/dist/docs/product/components/network-logo.md +248 -0
  55. package/dist/docs/product/components/number-field.md +543 -0
  56. package/dist/docs/product/components/otp-field.md +616 -0
  57. package/dist/docs/product/components/pagination.md +516 -0
  58. package/dist/docs/product/components/popover.md +544 -0
  59. package/dist/docs/product/components/progress.md +388 -0
  60. package/dist/docs/product/components/qr.md +314 -0
  61. package/dist/docs/product/components/radio-group.md +528 -0
  62. package/dist/docs/product/components/secret-value.md +406 -0
  63. package/dist/docs/product/components/select.md +751 -0
  64. package/dist/docs/product/components/separator.md +379 -0
  65. package/dist/docs/product/components/sidebar-menu.md +922 -0
  66. package/dist/docs/product/components/skeleton.md +517 -0
  67. package/dist/docs/product/components/slider.md +539 -0
  68. package/dist/docs/product/components/snippet.md +424 -0
  69. package/dist/docs/product/components/spinner.md +216 -0
  70. package/dist/docs/product/components/split-bar.md +139 -0
  71. package/dist/docs/product/components/split-button.md +464 -0
  72. package/dist/docs/product/components/stack.md +299 -0
  73. package/dist/docs/product/components/status-chip.md +226 -0
  74. package/dist/docs/product/components/status-indicator.md +119 -0
  75. package/dist/docs/product/components/status-row.md +174 -0
  76. package/dist/docs/product/components/stepper.md +451 -0
  77. package/dist/docs/product/components/success-hero.md +157 -0
  78. package/dist/docs/product/components/surface.md +639 -0
  79. package/dist/docs/product/components/switch.md +472 -0
  80. package/dist/docs/product/components/table.md +967 -0
  81. package/dist/docs/product/components/tabs.md +627 -0
  82. package/dist/docs/product/components/tempo-logo.md +185 -0
  83. package/dist/docs/product/components/text-input.md +624 -0
  84. package/dist/docs/product/components/textarea.md +352 -0
  85. package/dist/docs/product/components/toast.md +535 -0
  86. package/dist/docs/product/components/token-logo.md +371 -0
  87. package/dist/docs/product/components/token.md +247 -0
  88. package/dist/docs/product/components/tooltip.md +490 -0
  89. package/dist/docs/product/components/verification-code.md +116 -0
  90. package/dist/docs/product/components/visual.md +249 -0
  91. package/dist/docs/product/components.md +203 -0
  92. package/dist/docs/product/foundations/accessibility.md +377 -0
  93. package/dist/docs/product/foundations/agents.md +150 -0
  94. package/dist/docs/product/foundations/color.md +522 -0
  95. package/dist/docs/product/foundations/content/tone.md +194 -0
  96. package/dist/docs/product/foundations/content/voice.md +194 -0
  97. package/dist/docs/product/foundations/content/writing-style.md +406 -0
  98. package/dist/docs/product/foundations/iconography.md +282 -0
  99. package/dist/docs/product/foundations/intent.md +360 -0
  100. package/dist/docs/product/foundations/layout.md +508 -0
  101. package/dist/docs/product/foundations/linter.md +496 -0
  102. package/dist/docs/product/foundations/motion.md +151 -0
  103. package/dist/docs/product/foundations/radius-and-padding.md +86 -0
  104. package/dist/docs/product/foundations/typography.md +266 -0
  105. package/dist/docs/product/introduction/faq.md +133 -0
  106. package/dist/docs/product/introduction/getting-started.md +377 -0
  107. package/dist/docs/product/patterns/blockchain-values.md +709 -0
  108. package/dist/docs/product/patterns/dashboards.md +638 -0
  109. package/dist/docs/product/patterns/destructive-actions.md +626 -0
  110. package/dist/docs/product/patterns/empty-states.md +612 -0
  111. package/dist/docs/product/patterns/errors-and-validation.md +808 -0
  112. package/dist/docs/product/patterns/feedback-and-status.md +518 -0
  113. package/dist/docs/product/patterns/forms.md +679 -0
  114. package/dist/docs/product/patterns/loading.md +630 -0
  115. package/dist/docs/product/patterns/navigation.md +397 -0
  116. package/dist/docs/product/patterns/payments.md +765 -0
  117. package/dist/docs/product/patterns/responsive-layout.md +997 -0
  118. package/dist/docs/product/patterns/tables-and-lists.md +964 -0
  119. package/dist/docs/product/products/tempo-console.md +671 -0
  120. package/dist/docs/product/products/tempo-performance.md +437 -0
  121. package/dist/docs/product/products/tempo-wallet.md +438 -0
  122. package/dist/marketing/index.d.ts +4 -0
  123. package/dist/marketing/index.d.ts.map +1 -0
  124. package/dist/marketing/index.js +4 -0
  125. package/dist/marketing/index.js.map +1 -0
  126. package/dist/marketing/index.js.zyzz.json +1 -0
  127. package/dist/marketing/vars.d.ts +907 -0
  128. package/dist/marketing/vars.d.ts.map +1 -0
  129. package/dist/marketing/vars.js +15 -0
  130. package/dist/marketing/vars.js.map +1 -0
  131. package/dist/marketing/vars.js.zyzz.json +1 -0
  132. package/dist/marketing/zyzz.config.d.ts +4512 -0
  133. package/dist/marketing/zyzz.config.d.ts.map +1 -0
  134. package/dist/marketing/zyzz.config.js +63 -0
  135. package/dist/marketing/zyzz.config.js.map +1 -0
  136. package/dist/marketing/zyzz.config.js.zyzz.json +1 -0
  137. package/dist/oxlint/index.d.ts +12 -1
  138. package/dist/oxlint/index.d.ts.map +1 -1
  139. package/dist/oxlint/index.js +39 -1
  140. package/dist/oxlint/index.js.map +1 -1
  141. package/dist/oxlint/internal/Docs.d.ts +9 -0
  142. package/dist/oxlint/internal/Docs.d.ts.map +1 -0
  143. package/dist/oxlint/internal/Docs.js +15 -0
  144. package/dist/oxlint/internal/Docs.js.map +1 -0
  145. package/dist/oxlint/internal/Imports.d.ts +1 -1
  146. package/dist/oxlint/internal/Imports.d.ts.map +1 -1
  147. package/dist/oxlint/internal/Imports.js +2 -0
  148. package/dist/oxlint/internal/Imports.js.map +1 -1
  149. package/dist/oxlint/internal/Styles.d.ts +40 -0
  150. package/dist/oxlint/internal/Styles.d.ts.map +1 -0
  151. package/dist/oxlint/internal/Styles.js +194 -0
  152. package/dist/oxlint/internal/Styles.js.map +1 -0
  153. package/dist/oxlint/internal/Tokens.d.ts +16 -0
  154. package/dist/oxlint/internal/Tokens.d.ts.map +1 -0
  155. package/dist/oxlint/internal/Tokens.js +39 -0
  156. package/dist/oxlint/internal/Tokens.js.map +1 -0
  157. package/dist/oxlint/rules/NoCrossSurface.d.ts +2 -2
  158. package/dist/oxlint/rules/NoCrossSurface.js +3 -3
  159. package/dist/oxlint/rules/NoCrossSurface.js.map +1 -1
  160. package/dist/oxlint/rules/NoCustomValues.d.ts +11 -0
  161. package/dist/oxlint/rules/NoCustomValues.d.ts.map +1 -0
  162. package/dist/oxlint/rules/NoCustomValues.js +150 -0
  163. package/dist/oxlint/rules/NoCustomValues.js.map +1 -0
  164. package/dist/oxlint/rules/NoSingleKeyShortcuts.d.ts +11 -0
  165. package/dist/oxlint/rules/NoSingleKeyShortcuts.d.ts.map +1 -0
  166. package/dist/oxlint/rules/NoSingleKeyShortcuts.js +158 -0
  167. package/dist/oxlint/rules/NoSingleKeyShortcuts.js.map +1 -0
  168. package/dist/oxlint/rules/PreferComponent.d.ts +3 -2
  169. package/dist/oxlint/rules/PreferComponent.d.ts.map +1 -1
  170. package/dist/oxlint/rules/PreferComponent.js +11 -4
  171. package/dist/oxlint/rules/PreferComponent.js.map +1 -1
  172. package/dist/oxlint/rules/PreferLayout.d.ts +9 -0
  173. package/dist/oxlint/rules/PreferLayout.d.ts.map +1 -0
  174. package/dist/oxlint/rules/PreferLayout.js +90 -0
  175. package/dist/oxlint/rules/PreferLayout.js.map +1 -0
  176. package/dist/oxlint/rules/PreferProgress.d.ts +9 -0
  177. package/dist/oxlint/rules/PreferProgress.d.ts.map +1 -0
  178. package/dist/oxlint/rules/PreferProgress.js +43 -0
  179. package/dist/oxlint/rules/PreferProgress.js.map +1 -0
  180. package/dist/oxlint/rules/PreferSurface.d.ts +9 -0
  181. package/dist/oxlint/rules/PreferSurface.d.ts.map +1 -0
  182. package/dist/oxlint/rules/PreferSurface.js +55 -0
  183. package/dist/oxlint/rules/PreferSurface.js.map +1 -0
  184. package/dist/oxlint/rules/RequireAccessibleName.d.ts.map +1 -1
  185. package/dist/oxlint/rules/RequireAccessibleName.js +3 -1
  186. package/dist/oxlint/rules/RequireAccessibleName.js.map +1 -1
  187. package/dist/oxlint/rules/RequireScrollRegion.d.ts +11 -0
  188. package/dist/oxlint/rules/RequireScrollRegion.d.ts.map +1 -0
  189. package/dist/oxlint/rules/RequireScrollRegion.js +71 -0
  190. package/dist/oxlint/rules/RequireScrollRegion.js.map +1 -0
  191. package/dist/web/icons/index.js.zyzz.json +1 -0
  192. package/package.json +6 -1
  193. package/src/marketing/README.md +21 -0
  194. package/src/marketing/index.ts +3 -0
  195. package/src/marketing/vars.ts +751 -0
  196. package/src/marketing/zyzz.config.ts +376 -0
  197. package/src/oxlint/index.ts +40 -1
  198. package/src/oxlint/internal/Docs.ts +18 -0
  199. package/src/oxlint/internal/Imports.ts +2 -1
  200. package/src/oxlint/internal/Styles.ts +240 -0
  201. package/src/oxlint/internal/Tokens.ts +43 -0
  202. package/src/oxlint/rules/NoCrossSurface.ts +3 -3
  203. package/src/oxlint/rules/NoCustomValues.ts +170 -0
  204. package/src/oxlint/rules/NoSingleKeyShortcuts.ts +190 -0
  205. package/src/oxlint/rules/PreferComponent.ts +11 -4
  206. package/src/oxlint/rules/PreferLayout.ts +96 -0
  207. package/src/oxlint/rules/PreferProgress.ts +49 -0
  208. package/src/oxlint/rules/PreferSurface.ts +70 -0
  209. package/src/oxlint/rules/RequireAccessibleName.ts +3 -1
  210. package/src/oxlint/rules/RequireScrollRegion.ts +92 -0
@@ -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](copy-button.md) to copy a value, and [SplitButton](split-button.md) for a main action with related alternatives.
274
+ * Use [Tabs](tabs.md) or [ChoiceGroup](choice-group.md) to switch views, and [Switch](switch.md) to turn a setting on or off.
275
+ * If a section has more than three secondary actions, put them in a [Menu](menu.md) 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](alert-dialog.md), whose confirming button takes `danger`. See [Destructive Actions](../patterns/destructive-actions.md) and [Payments](../patterns/payments.md).
284
+
285
+ ### Use One Primary Action
286
+
287
+ Give other actions `secondary` or `tertiary`, even if they matter. [Forms](../patterns/forms.md#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](button-group.md).
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](spinner.md) 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](tooltip.md). 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](tooltip.md) 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](../foundations/accessibility.md) 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](toast.md) or an [Alert](alert.md).
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](button-group.md)
629
+
630
+ Use for the actions at the foot of a dialog.
631
+
632
+ [SplitButton](split-button.md)
633
+
634
+ Use for a main action with alternatives.
635
+
636
+ [CopyButton](copy-button.md)
637
+
638
+ Use for copying a value.
639
+
640
+ [AlertDialog](alert-dialog.md)
641
+
642
+ Use for confirming an action.
643
+
644
+ [Forms](../patterns/forms.md)
645
+
646
+ Covers placing submit and cancel actions.
647
+
648
+ [Destructive Actions](../patterns/destructive-actions.md)
649
+
650
+ Covers deleting and revoking.