@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.
Files changed (120) hide show
  1. package/dist/docs/AGENTS.md +9 -0
  2. package/dist/docs/components/accordion.md +489 -0
  3. package/dist/docs/components/address-card.md +147 -0
  4. package/dist/docs/components/agent-logo.md +194 -0
  5. package/dist/docs/components/alert-dialog.md +631 -0
  6. package/dist/docs/components/alert.md +448 -0
  7. package/dist/docs/components/amount-input.md +305 -0
  8. package/dist/docs/components/amount.md +794 -0
  9. package/dist/docs/components/app-shell.md +559 -0
  10. package/dist/docs/components/asset-chip.md +294 -0
  11. package/dist/docs/components/autocomplete.md +619 -0
  12. package/dist/docs/components/avatar.md +321 -0
  13. package/dist/docs/components/badge.md +339 -0
  14. package/dist/docs/components/badged-logo.md +116 -0
  15. package/dist/docs/components/banner.md +379 -0
  16. package/dist/docs/components/bar-chart.md +208 -0
  17. package/dist/docs/components/breadcrumbs.md +380 -0
  18. package/dist/docs/components/button-group.md +286 -0
  19. package/dist/docs/components/button.md +650 -0
  20. package/dist/docs/components/calendar.md +375 -0
  21. package/dist/docs/components/callout.md +96 -0
  22. package/dist/docs/components/checkbox-group.md +521 -0
  23. package/dist/docs/components/checkbox.md +467 -0
  24. package/dist/docs/components/choice-group.md +516 -0
  25. package/dist/docs/components/choicebox.md +641 -0
  26. package/dist/docs/components/code.md +100 -0
  27. package/dist/docs/components/combobox.md +939 -0
  28. package/dist/docs/components/container.md +257 -0
  29. package/dist/docs/components/copy-button.md +642 -0
  30. package/dist/docs/components/date-picker.md +514 -0
  31. package/dist/docs/components/dialog.md +1332 -0
  32. package/dist/docs/components/drawer.md +966 -0
  33. package/dist/docs/components/empty.md +340 -0
  34. package/dist/docs/components/field.md +570 -0
  35. package/dist/docs/components/fieldset.md +398 -0
  36. package/dist/docs/components/frame.md +434 -0
  37. package/dist/docs/components/gauge.md +299 -0
  38. package/dist/docs/components/get-started-visual.md +117 -0
  39. package/dist/docs/components/grid.md +288 -0
  40. package/dist/docs/components/hero-visual.md +155 -0
  41. package/dist/docs/components/hex.md +487 -0
  42. package/dist/docs/components/icon-tile.md +292 -0
  43. package/dist/docs/components/identicon.md +371 -0
  44. package/dist/docs/components/inline.md +233 -0
  45. package/dist/docs/components/inset.md +225 -0
  46. package/dist/docs/components/kbd.md +423 -0
  47. package/dist/docs/components/list-group.md +981 -0
  48. package/dist/docs/components/loading-dots.md +237 -0
  49. package/dist/docs/components/menu.md +934 -0
  50. package/dist/docs/components/native-select.md +204 -0
  51. package/dist/docs/components/network-logo.md +248 -0
  52. package/dist/docs/components/number-field.md +543 -0
  53. package/dist/docs/components/otp-field.md +616 -0
  54. package/dist/docs/components/pagination.md +516 -0
  55. package/dist/docs/components/popover.md +544 -0
  56. package/dist/docs/components/progress.md +388 -0
  57. package/dist/docs/components/qr.md +314 -0
  58. package/dist/docs/components/radio-group.md +528 -0
  59. package/dist/docs/components/secret-value.md +406 -0
  60. package/dist/docs/components/select.md +751 -0
  61. package/dist/docs/components/separator.md +379 -0
  62. package/dist/docs/components/sidebar-menu.md +922 -0
  63. package/dist/docs/components/skeleton.md +517 -0
  64. package/dist/docs/components/slider.md +539 -0
  65. package/dist/docs/components/snippet.md +424 -0
  66. package/dist/docs/components/spinner.md +216 -0
  67. package/dist/docs/components/split-bar.md +139 -0
  68. package/dist/docs/components/split-button.md +464 -0
  69. package/dist/docs/components/stack.md +299 -0
  70. package/dist/docs/components/status-chip.md +226 -0
  71. package/dist/docs/components/status-indicator.md +119 -0
  72. package/dist/docs/components/status-row.md +174 -0
  73. package/dist/docs/components/stepper.md +451 -0
  74. package/dist/docs/components/success-hero.md +157 -0
  75. package/dist/docs/components/surface.md +639 -0
  76. package/dist/docs/components/switch.md +472 -0
  77. package/dist/docs/components/table.md +967 -0
  78. package/dist/docs/components/tabs.md +627 -0
  79. package/dist/docs/components/tempo-logo.md +185 -0
  80. package/dist/docs/components/text-input.md +624 -0
  81. package/dist/docs/components/textarea.md +352 -0
  82. package/dist/docs/components/toast.md +535 -0
  83. package/dist/docs/components/token-logo.md +371 -0
  84. package/dist/docs/components/token.md +247 -0
  85. package/dist/docs/components/tooltip.md +490 -0
  86. package/dist/docs/components/verification-code.md +116 -0
  87. package/dist/docs/components/visual.md +249 -0
  88. package/dist/docs/components.md +203 -0
  89. package/dist/docs/foundations/accessibility.md +377 -0
  90. package/dist/docs/foundations/agents.md +150 -0
  91. package/dist/docs/foundations/color.md +522 -0
  92. package/dist/docs/foundations/content/tone.md +194 -0
  93. package/dist/docs/foundations/content/voice.md +194 -0
  94. package/dist/docs/foundations/content/writing-style.md +406 -0
  95. package/dist/docs/foundations/iconography.md +282 -0
  96. package/dist/docs/foundations/intent.md +360 -0
  97. package/dist/docs/foundations/layout.md +508 -0
  98. package/dist/docs/foundations/linter.md +296 -0
  99. package/dist/docs/foundations/motion.md +151 -0
  100. package/dist/docs/foundations/radius-and-padding.md +86 -0
  101. package/dist/docs/foundations/typography.md +266 -0
  102. package/dist/docs/index.md +137 -0
  103. package/dist/docs/introduction/faq.md +132 -0
  104. package/dist/docs/introduction/getting-started.md +377 -0
  105. package/dist/docs/patterns/blockchain-values.md +709 -0
  106. package/dist/docs/patterns/dashboards.md +638 -0
  107. package/dist/docs/patterns/destructive-actions.md +626 -0
  108. package/dist/docs/patterns/empty-states.md +612 -0
  109. package/dist/docs/patterns/errors-and-validation.md +808 -0
  110. package/dist/docs/patterns/feedback-and-status.md +518 -0
  111. package/dist/docs/patterns/forms.md +679 -0
  112. package/dist/docs/patterns/loading.md +630 -0
  113. package/dist/docs/patterns/navigation.md +397 -0
  114. package/dist/docs/patterns/payments.md +765 -0
  115. package/dist/docs/patterns/responsive-layout.md +997 -0
  116. package/dist/docs/patterns/tables-and-lists.md +964 -0
  117. package/dist/docs/products/tempo-console.md +671 -0
  118. package/dist/docs/products/tempo-performance.md +437 -0
  119. package/dist/docs/products/tempo-wallet.md +438 -0
  120. package/package.json +1 -1
@@ -0,0 +1,642 @@
1
+ # CopyButton
2
+
3
+ Copies a value to the clipboard and confirms the copy.
4
+
5
+ [View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/CopyButton.tsx)
6
+
7
+ ## Overview
8
+
9
+ A copy button is an icon-only button that writes a value to the clipboard and confirms the copy for two seconds.
10
+
11
+ ## Examples
12
+
13
+ ### Basic
14
+
15
+ ```tsx
16
+ import { CopyButton } from '@tempoxyz/ds'
17
+
18
+ export function Demo() {
19
+ return <CopyButton value="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" />
20
+ }
21
+ ```
22
+
23
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/CopyButton/Basic.tsx)
24
+
25
+ ### Size
26
+
27
+ Set `size` to `small` (default), `medium`, or `large`.
28
+
29
+ ```tsx
30
+ import { CopyButton, style } from '@tempoxyz/ds'
31
+
32
+ const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
33
+
34
+ export function Demo() {
35
+ return (
36
+ <div {...styles.row()}>
37
+ {(['small', 'medium', 'large'] as const).map((size) => (
38
+ <CopyButton key={size} size={size} value={address} />
39
+ ))}
40
+ </div>
41
+ )
42
+ }
43
+
44
+ namespace styles {
45
+ export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
46
+ }
47
+ ```
48
+
49
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/CopyButton/Size.tsx)
50
+
51
+ ### Variant
52
+
53
+ Set `variant` to any [Button](/docs/components/button) variant, such as `tertiary` (default) or `secondary`.
54
+
55
+ ```tsx
56
+ import { CopyButton, style } from '@tempoxyz/ds'
57
+
58
+ const address = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
59
+
60
+ export function Demo() {
61
+ return (
62
+ <div {...styles.row()}>
63
+ <CopyButton value={address} />
64
+ <CopyButton value={address} variant="secondary" />
65
+ <CopyButton size="medium" value={address} variant="secondary" />
66
+ </div>
67
+ )
68
+ }
69
+
70
+ namespace styles {
71
+ export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
72
+ }
73
+ ```
74
+
75
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/CopyButton/Variant.tsx)
76
+
77
+ ### Disabled
78
+
79
+ ```tsx
80
+ import { CopyButton } from '@tempoxyz/ds'
81
+
82
+ export function Demo() {
83
+ return <CopyButton disabled value="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" />
84
+ }
85
+ ```
86
+
87
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/CopyButton/Disabled.tsx)
88
+
89
+ ## Anatomy
90
+
91
+ Import the component and assemble its parts.
92
+
93
+ ```tsx
94
+ import { CopyButton } from '@tempoxyz/ds'
95
+
96
+ <CopyButton />
97
+ ```
98
+
99
+ ## Guidelines
100
+
101
+ ### When to Use
102
+
103
+ * Copy a value you'd otherwise select by hand, such as a webhook ID or an invite link.
104
+ * Add copying beside a value in your own layout, such as a table cell.
105
+
106
+ ### When Not to Use
107
+
108
+ * Use [Hex](/docs/components/hex) with `copy` for addresses and transaction hashes. It truncates the middle and adds this button.
109
+ * Use [Snippet](/docs/components/snippet) for a command or code value.
110
+ * Use [SecretValue](/docs/components/secret-value) for API keys and other secrets that stay hidden until revealed.
111
+ * Use a [Button](/docs/components/button) for other actions, such as Share or Download.
112
+
113
+ ### Place It Right After the Value
114
+
115
+ Put the button on the same line, immediately after the value. Give each value its own button.
116
+
117
+ **Do:** Place a copy button directly after each value.
118
+
119
+ ```tsx
120
+ /**
121
+ * Do example for "Place It Right After the Value" on the CopyButton page.
122
+ * Place a copy button directly after each value.
123
+ * @module
124
+ */
125
+ import { CopyButton, style } from '@tempoxyz/ds'
126
+
127
+ /** Renders the static preview, which the guideline card shows inert. */
128
+ export function Demo() {
129
+ return (
130
+ <div {...styles.rows()}>
131
+ <div {...styles.row()}>
132
+ <span {...styles.label()}>Webhook ID</span>
133
+ <span {...styles.value()}>
134
+ wh_51c8e20d
135
+ <CopyButton aria-label="Copy webhook ID" value="wh_51c8e20d" />
136
+ </span>
137
+ </div>
138
+ <div {...styles.row()}>
139
+ <span {...styles.label()}>Key ID</span>
140
+ <span {...styles.value()}>
141
+ key_9f2c41a7
142
+ <CopyButton aria-label="Copy key ID" value="key_9f2c41a7" />
143
+ </span>
144
+ </div>
145
+ </div>
146
+ )
147
+ }
148
+
149
+ namespace styles {
150
+ export const label = style({ color: 'content.secondary', typography: 'body.b2' })
151
+
152
+ export const row = style({
153
+ alignItems: 'center',
154
+ display: 'flex',
155
+ justifyContent: 'space-between',
156
+ minHeight: '32',
157
+ })
158
+
159
+ export const rows = style({
160
+ display: 'flex',
161
+ flexDirection: 'column',
162
+ rowGap: '8',
163
+ width: '16rem !custom',
164
+ })
165
+
166
+ export const value = style({
167
+ alignItems: 'center',
168
+ color: 'content.primary',
169
+ columnGap: '4',
170
+ display: 'flex',
171
+ typography: 'mono.m1',
172
+ })
173
+ }
174
+ ```
175
+
176
+ **Don't:** Place one copy button away from the values, where its target is unclear.
177
+
178
+ ```tsx
179
+ /**
180
+ * Don't example for "Place It Right After the Value" on the CopyButton page.
181
+ * Don't place one copy button away from the values, where its target is unclear.
182
+ * @module
183
+ */
184
+ import { CopyButton, style } from '@tempoxyz/ds'
185
+
186
+ /** Renders the static preview, which the guideline card shows inert. */
187
+ export function Demo() {
188
+ return (
189
+ <div {...styles.rows()}>
190
+ <div {...styles.header()}>
191
+ <span {...styles.title()}>Webhook</span>
192
+ <CopyButton aria-label="Copy" value="wh_51c8e20d" />
193
+ </div>
194
+ <div {...styles.row()}>
195
+ <span {...styles.label()}>Webhook ID</span>
196
+ <span {...styles.value()}>wh_51c8e20d</span>
197
+ </div>
198
+ <div {...styles.row()}>
199
+ <span {...styles.label()}>Key ID</span>
200
+ <span {...styles.value()}>key_9f2c41a7</span>
201
+ </div>
202
+ </div>
203
+ )
204
+ }
205
+
206
+ namespace styles {
207
+ export const header = style({
208
+ alignItems: 'center',
209
+ display: 'flex',
210
+ justifyContent: 'space-between',
211
+ marginBottom: '4',
212
+ })
213
+
214
+ export const label = style({ color: 'content.secondary', typography: 'body.b2' })
215
+
216
+ export const row = style({
217
+ alignItems: 'center',
218
+ display: 'flex',
219
+ justifyContent: 'space-between',
220
+ minHeight: '32',
221
+ })
222
+
223
+ export const rows = style({
224
+ display: 'flex',
225
+ flexDirection: 'column',
226
+ rowGap: '8',
227
+ width: '16rem !custom',
228
+ })
229
+
230
+ export const title = style({ color: 'content.primary', typography: 'body.b1Strong' })
231
+
232
+ export const value = style({ color: 'content.primary', typography: 'mono.m1' })
233
+ }
234
+ ```
235
+
236
+ ### Copy the Full Value
237
+
238
+ Pass the complete value to `value`, even when the screen shows a shortened form.
239
+
240
+ **Do:** Copy the complete value behind a shortened display.
241
+
242
+ ```tsx
243
+ /**
244
+ * Do example for "Copy the Full Value" on the CopyButton page.
245
+ * Copy the complete value behind a shortened display.
246
+ * @module
247
+ */
248
+ import { CopyButton, style } from '@tempoxyz/ds'
249
+
250
+ const url = 'https://hooks.tempo.xyz/v1/payments/wh_51c8e20d'
251
+
252
+ /** Renders the static preview, which the guideline card shows inert. */
253
+ export function Demo() {
254
+ return (
255
+ <div {...styles.stack()}>
256
+ <span {...styles.value()}>
257
+ hooks.tempo.xyz/…/wh_51c8e20d
258
+ <CopyButton aria-label="Copy webhook URL" copied value={url} />
259
+ </span>
260
+ <div {...styles.clipboard()}>
261
+ <span {...styles.label()}>Clipboard</span>
262
+ <span {...styles.copied()}>{url}</span>
263
+ </div>
264
+ </div>
265
+ )
266
+ }
267
+
268
+ namespace styles {
269
+ export const clipboard = style({
270
+ backgroundColor: 'container.regular',
271
+ borderRadius: '2xs',
272
+ display: 'flex',
273
+ flexDirection: 'column',
274
+ paddingBlock: '8',
275
+ paddingInline: '12',
276
+ rowGap: '2px !custom',
277
+ })
278
+
279
+ export const copied = style({ color: 'content.primary', typography: 'mono.m1' })
280
+
281
+ export const label = style({ color: 'content.secondary', typography: 'body.b3' })
282
+
283
+ export const stack = style({
284
+ display: 'flex',
285
+ flexDirection: 'column',
286
+ rowGap: '8',
287
+ width: '17rem !custom',
288
+ })
289
+
290
+ export const value = style({
291
+ alignItems: 'center',
292
+ color: 'content.primary',
293
+ columnGap: '4',
294
+ display: 'flex',
295
+ typography: 'mono.m1',
296
+ })
297
+ }
298
+ ```
299
+
300
+ **Don't:** Copy the shortened text that the screen shows.
301
+
302
+ ```tsx
303
+ /**
304
+ * Don't example for "Copy the Full Value" on the CopyButton page.
305
+ * Don't copy the shortened text that the screen shows.
306
+ * @module
307
+ */
308
+ import { CopyButton, style } from '@tempoxyz/ds'
309
+
310
+ const display = 'hooks.tempo.xyz/…/wh_51c8e20d'
311
+
312
+ /** Renders the static preview, which the guideline card shows inert. */
313
+ export function Demo() {
314
+ return (
315
+ <div {...styles.stack()}>
316
+ <span {...styles.value()}>
317
+ {display}
318
+ <CopyButton aria-label="Copy webhook URL" copied value={display} />
319
+ </span>
320
+ <div {...styles.clipboard()}>
321
+ <span {...styles.label()}>Clipboard</span>
322
+ <span {...styles.copied()}>{display}</span>
323
+ </div>
324
+ </div>
325
+ )
326
+ }
327
+
328
+ namespace styles {
329
+ export const clipboard = style({
330
+ backgroundColor: 'container.regular',
331
+ borderRadius: '2xs',
332
+ display: 'flex',
333
+ flexDirection: 'column',
334
+ paddingBlock: '8',
335
+ paddingInline: '12',
336
+ rowGap: '2px !custom',
337
+ })
338
+
339
+ export const copied = style({ color: 'content.primary', typography: 'mono.m1' })
340
+
341
+ export const label = style({ color: 'content.secondary', typography: 'body.b3' })
342
+
343
+ export const stack = style({
344
+ display: 'flex',
345
+ flexDirection: 'column',
346
+ rowGap: '8',
347
+ width: '17rem !custom',
348
+ })
349
+
350
+ export const value = style({
351
+ alignItems: 'center',
352
+ color: 'content.primary',
353
+ columnGap: '4',
354
+ display: 'flex',
355
+ typography: 'mono.m1',
356
+ })
357
+ }
358
+ ```
359
+
360
+ ### Keep the Built-In Confirmation
361
+
362
+ After a copy, the icon turns into a check for two seconds and screen readers announce Copied. If the clipboard refuses the write, the button shows no confirmation and doesn't call `onCopy`, so keep the value selectable as text.
363
+
364
+ **Do:** Let the check icon confirm the copy.
365
+
366
+ ```tsx
367
+ /**
368
+ * Do example for "Keep the Built-In Confirmation" on the CopyButton page.
369
+ * Let the check icon confirm the copy.
370
+ * @module
371
+ */
372
+ import { CopyButton, style } from '@tempoxyz/ds'
373
+
374
+ /** Renders the static preview, which the guideline card shows inert. */
375
+ export function Demo() {
376
+ return (
377
+ <div {...styles.stack()}>
378
+ <div {...styles.row()}>
379
+ <span {...styles.label()}>Webhook ID</span>
380
+ <span {...styles.value()}>
381
+ wh_51c8e20d
382
+ <CopyButton aria-label="Copy webhook ID" copied value="wh_51c8e20d" />
383
+ </span>
384
+ </div>
385
+ </div>
386
+ )
387
+ }
388
+
389
+ namespace styles {
390
+ export const label = style({ color: 'content.secondary', typography: 'body.b2' })
391
+
392
+ export const row = style({
393
+ alignItems: 'center',
394
+ display: 'flex',
395
+ justifyContent: 'space-between',
396
+ minHeight: '32',
397
+ })
398
+
399
+ export const stack = style({
400
+ display: 'flex',
401
+ flexDirection: 'column',
402
+ rowGap: '16',
403
+ width: '16rem !custom',
404
+ })
405
+
406
+ export const value = style({
407
+ alignItems: 'center',
408
+ color: 'content.primary',
409
+ columnGap: '4',
410
+ display: 'flex',
411
+ typography: 'mono.m1',
412
+ })
413
+ }
414
+ ```
415
+
416
+ **Don't:** Add a [Toast](/docs/components/toast) or text such as Copied to clipboard.
417
+
418
+ ```tsx
419
+ /**
420
+ * Don't example for "Keep the Built-In Confirmation" on the CopyButton page.
421
+ * Don't add a Toast or text such as Copied to clipboard.
422
+ * @module
423
+ */
424
+ import { CopyButton, style } from '@tempoxyz/ds'
425
+ import { CheckCircle } from '@tempoxyz/ds/icons'
426
+
427
+ // Toasts render in a portal, so this preview draws one in place with the toast's styles.
428
+ /** Renders the static preview, which the guideline card shows inert. */
429
+ export function Demo() {
430
+ return (
431
+ <div {...styles.stack()}>
432
+ <div {...styles.row()}>
433
+ <span {...styles.label()}>Webhook ID</span>
434
+ <span {...styles.value()}>
435
+ wh_51c8e20d
436
+ <CopyButton aria-label="Copy webhook ID" copied value="wh_51c8e20d" />
437
+ </span>
438
+ </div>
439
+ <div {...styles.toast()}>
440
+ <CheckCircle {...styles.icon()} />
441
+ <span {...styles.title()}>Copied to clipboard</span>
442
+ </div>
443
+ </div>
444
+ )
445
+ }
446
+
447
+ namespace styles {
448
+ export const icon = style({ color: 'content.positive', flexShrink: '0 !custom', fontSize: '20' })
449
+
450
+ export const label = style({ color: 'content.secondary', typography: 'body.b2' })
451
+
452
+ export const row = style({
453
+ alignItems: 'center',
454
+ display: 'flex',
455
+ justifyContent: 'space-between',
456
+ minHeight: '32',
457
+ })
458
+
459
+ export const stack = style({
460
+ display: 'flex',
461
+ flexDirection: 'column',
462
+ rowGap: '16',
463
+ width: '16rem !custom',
464
+ })
465
+
466
+ export const title = style({ color: 'content.primary', typography: 'body.b2Strong' })
467
+
468
+ export const toast = style({
469
+ alignItems: 'center',
470
+ backgroundColor: 'background.elevated',
471
+ borderRadius: 'sm',
472
+ boxShadow: 'regular',
473
+ boxSizing: 'border-box',
474
+ columnGap: '12',
475
+ display: 'flex',
476
+ paddingBlock: '16',
477
+ paddingInline: '20',
478
+ })
479
+
480
+ export const value = style({
481
+ alignItems: 'center',
482
+ color: 'content.primary',
483
+ columnGap: '4',
484
+ display: 'flex',
485
+ typography: 'mono.m1',
486
+ })
487
+ }
488
+ ```
489
+
490
+ ### Choose a Variant by Context
491
+
492
+ * **Text (default):** Inline values in rows, tables, and cards.
493
+ * **Secondary (secondary):** A standalone value you mainly copy, such as an invite link.
494
+
495
+ Keep `small` beside body text. Use `medium` or `large` in touch layouts, or beside a large value or a control of that size.
496
+
497
+ ### Let a Clickable Row Copy
498
+
499
+ If a whole row copies on press, handle the copy in the row and pass `copied` to the button. The button shows the confirmation without a second copy. [Snippet](/docs/components/snippet) and [SecretValue](/docs/components/secret-value) work this way.
500
+
501
+ **Do:** Pass `copied` so the button confirms the row's copy.
502
+
503
+ ```tsx
504
+ /**
505
+ * Do example for "Let a Clickable Row Copy" on the CopyButton page.
506
+ * Pass `copied` so the button confirms the row's copy.
507
+ * @module
508
+ */
509
+ import { CopyButton, style } from '@tempoxyz/ds'
510
+
511
+ /** Renders the static preview, which the guideline card shows inert. */
512
+ export function Demo() {
513
+ return (
514
+ <div {...styles.row()}>
515
+ <span {...styles.label()}>Invite link</span>
516
+ <span {...styles.value()}>
517
+ tempo.xyz/invite/7kq2
518
+ <CopyButton aria-label="Copy invite link" copied value="https://tempo.xyz/invite/7kq2" />
519
+ </span>
520
+ </div>
521
+ )
522
+ }
523
+
524
+ namespace styles {
525
+ export const label = style({ color: 'content.secondary', typography: 'body.b2' })
526
+
527
+ // The pressed row draws its hover background, since the preview is inert.
528
+ export const row = style({
529
+ alignItems: 'center',
530
+ backgroundColor: 'container.regular',
531
+ borderRadius: 'xs',
532
+ boxSizing: 'border-box',
533
+ display: 'flex',
534
+ justifyContent: 'space-between',
535
+ minHeight: '40',
536
+ paddingInline: '12',
537
+ width: '17rem !custom',
538
+ })
539
+
540
+ export const value = style({
541
+ alignItems: 'center',
542
+ color: 'content.primary',
543
+ columnGap: '4',
544
+ display: 'flex',
545
+ typography: 'mono.m1',
546
+ })
547
+ }
548
+ ```
549
+
550
+ **Don't:** Leave the button unconfirmed after the row copies.
551
+
552
+ ```tsx
553
+ /**
554
+ * Don't example for "Let a Clickable Row Copy" on the CopyButton page.
555
+ * Don't leave the button unconfirmed after the row copies.
556
+ * @module
557
+ */
558
+ import { CopyButton, style } from '@tempoxyz/ds'
559
+
560
+ /** Renders the static preview, which the guideline card shows inert. */
561
+ export function Demo() {
562
+ return (
563
+ <div {...styles.row()}>
564
+ <span {...styles.label()}>Invite link</span>
565
+ <span {...styles.value()}>
566
+ tempo.xyz/invite/7kq2
567
+ <CopyButton aria-label="Copy invite link" value="https://tempo.xyz/invite/7kq2" />
568
+ </span>
569
+ </div>
570
+ )
571
+ }
572
+
573
+ namespace styles {
574
+ export const label = style({ color: 'content.secondary', typography: 'body.b2' })
575
+
576
+ // The pressed row draws its hover background, since the preview is inert.
577
+ export const row = style({
578
+ alignItems: 'center',
579
+ backgroundColor: 'container.regular',
580
+ borderRadius: 'xs',
581
+ boxSizing: 'border-box',
582
+ display: 'flex',
583
+ justifyContent: 'space-between',
584
+ minHeight: '40',
585
+ paddingInline: '12',
586
+ width: '17rem !custom',
587
+ })
588
+
589
+ export const value = style({
590
+ alignItems: 'center',
591
+ color: 'content.primary',
592
+ columnGap: '4',
593
+ display: 'flex',
594
+ typography: 'mono.m1',
595
+ })
596
+ }
597
+ ```
598
+
599
+ ## Accessibility
600
+
601
+ A copy button renders an icon-only [Button](/docs/components/button) with a visually hidden status message. It follows the [WAI-ARIA Authoring Practices button pattern](https://www.w3.org/WAI/ARIA/apg/patterns/button/).
602
+
603
+ ### Semantics
604
+
605
+ * **Button (button):** A native button. Enter and Space copy, and it joins the tab order.
606
+ * **Name (aria-label):** Defaults to "Copy" and the value. Shows on hover, not on focus or touch.
607
+ * **Copied State (2s):** After a copy, the name changes to "Copied", then returns.
608
+ * **Status Region (status):** A polite live region holds the confirmation text.
609
+ * **Disabled (disabled):** Removes the button from the tab order unless you set `focusableWhenDisabled`.
610
+ * **Clipboard Fallback (execCommand):** Copies where the Clipboard API is unavailable, such as insecure contexts and some iframes.
611
+
612
+ ### Keyboard
613
+
614
+ * **Move Focus to the Button (Tab):** Moves focus to the button.
615
+ * **Copy the Value (Enter or Space):** Copies the value.
616
+
617
+ ### Your Responsibilities
618
+
619
+ * **Name What It Copies (aria-label):** Name the value, such as "Copy address". A raw address reads poorly.
620
+ * **Announce Parent Failures (copied):** If a parent copies on its own click, announce failures from that parent.
621
+
622
+ ## Related
623
+
624
+ [Hex](/docs/components/hex)
625
+
626
+ Use for addresses and hashes with copying built in.
627
+
628
+ [Snippet](/docs/components/snippet)
629
+
630
+ Use for commands and code.
631
+
632
+ [SecretValue](/docs/components/secret-value)
633
+
634
+ Use for API keys and secrets.
635
+
636
+ [Button](/docs/components/button)
637
+
638
+ Use for other icon-only actions.
639
+
640
+ [Blockchain Values](/docs/patterns/blockchain-values)
641
+
642
+ Covers showing addresses, hashes, and amounts.