@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,490 @@
1
+ # Tooltip
2
+
3
+ Shows a short label for a control on hover or focus.
4
+
5
+ [View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/Tooltip.tsx)
6
+
7
+ Figma: [Tooltip](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=3084-1076) (`Tooltip.Popup`)
8
+
9
+ ## Overview
10
+
11
+ A tooltip is a visual label that opens on hover and keyboard focus.
12
+
13
+ ## Examples
14
+
15
+ ### Basic
16
+
17
+ ```tsx
18
+ import { Button, Tooltip } from '@tempoxyz/ds'
19
+ import { Plus } from '@tempoxyz/ds/icons'
20
+
21
+ export function Demo() {
22
+ return (
23
+ <Tooltip.Provider>
24
+ <Tooltip.Root>
25
+ <Tooltip.Trigger
26
+ render={<Button aria-label="Add funds" shape="icon" variant="secondary" />}
27
+ >
28
+ <Plus />
29
+ </Tooltip.Trigger>
30
+ <Tooltip.Popup>Add funds</Tooltip.Popup>
31
+ </Tooltip.Root>
32
+ </Tooltip.Provider>
33
+ )
34
+ }
35
+ ```
36
+
37
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Tooltip/Basic.tsx)
38
+
39
+ ### Side
40
+
41
+ Set `side` on `Tooltip.Popup` to `top` (default), `bottom`, `left`, or `right`.
42
+
43
+ ```tsx
44
+ import { Button, Tooltip } from '@tempoxyz/ds'
45
+
46
+ export function Demo() {
47
+ return (
48
+ <Tooltip.Provider>
49
+ <Tooltip.Root>
50
+ <Tooltip.Trigger render={<Button variant="secondary" />}>Bottom</Tooltip.Trigger>
51
+ <Tooltip.Popup side="bottom">Shown below the trigger</Tooltip.Popup>
52
+ </Tooltip.Root>
53
+ </Tooltip.Provider>
54
+ )
55
+ }
56
+ ```
57
+
58
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Tooltip/Side.tsx)
59
+
60
+ ### Disabled
61
+
62
+ Wrap a disabled control in a focusable trigger. Disabled elements receive no pointer or focus events.
63
+
64
+ ```tsx
65
+ import { Button, Tooltip } from '@tempoxyz/ds'
66
+ import { Refresh } from '@tempoxyz/ds/icons'
67
+
68
+ export function Demo() {
69
+ return (
70
+ <Tooltip.Provider>
71
+ <Tooltip.Root>
72
+ <Tooltip.Trigger render={<span tabIndex={0} />}>
73
+ <Button aria-label="Refresh balances" disabled shape="icon" variant="secondary">
74
+ <Refresh />
75
+ </Button>
76
+ </Tooltip.Trigger>
77
+ <Tooltip.Popup>Refresh balances</Tooltip.Popup>
78
+ </Tooltip.Root>
79
+ </Tooltip.Provider>
80
+ )
81
+ }
82
+ ```
83
+
84
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Tooltip/Disabled.tsx)
85
+
86
+ ## Anatomy
87
+
88
+ Import the component and assemble its parts.
89
+
90
+ ```tsx
91
+ import { Tooltip } from '@tempoxyz/ds'
92
+
93
+ <Tooltip.Provider>
94
+ <Tooltip.Root>
95
+ <Tooltip.Trigger />
96
+ <Tooltip.Popup />
97
+ </Tooltip.Root>
98
+ </Tooltip.Provider>
99
+ ```
100
+
101
+ ## Guidelines
102
+
103
+ ### When to Use
104
+
105
+ * Label an icon-only button, such as Refresh balances, Filter activity, or Settings.
106
+ * Name a control whose icon is ambiguous, such as an arrow that could mean Send or Export.
107
+
108
+ ### When Not to Use
109
+
110
+ * Use a [Popover](/docs/components/popover) with `openOnHover` on `Popover.Trigger` for info icons, such as the explanation beside a dashboard metric.
111
+ * Use visible text, such as a `Field.Description` from [Field](/docs/components/field), for fees, limits, requirements, and errors.
112
+ * Use an [Alert](/docs/components/alert) for warnings.
113
+ * Write the reason for a disabled [Button](/docs/components/button) in nearby text, not in a tooltip.
114
+ * Don't add a tooltip to a [Button](/docs/components/button) with a visible label. It repeats the label and covers nearby content.
115
+
116
+ ### Use Tooltips as Labels Only
117
+
118
+ Focus stays on the trigger while the tooltip is open, so Tab can't reach a link or button inside it.
119
+
120
+ **Do:** Name the action of an icon-only button in a few words.
121
+
122
+ ```tsx
123
+ /**
124
+ * Do example for "Use Tooltips as Labels Only" on the Tooltip page.
125
+ * Name the action of an icon-only button in a few words.
126
+ * @module
127
+ */
128
+ import { Button, style } from '@tempoxyz/ds'
129
+ import { Filter } from '@tempoxyz/ds/icons'
130
+
131
+ /** Renders the static preview, which the guideline card shows inert. */
132
+ export function Demo() {
133
+ return (
134
+ <div {...styles.stack()}>
135
+ <div {...styles.tooltip()}>Filter activity</div>
136
+ <Button aria-label="Filter activity" shape="icon" variant="secondary">
137
+ <Filter />
138
+ </Button>
139
+ </div>
140
+ )
141
+ }
142
+
143
+ namespace styles {
144
+ export const stack = style({
145
+ alignItems: 'center',
146
+ display: 'flex',
147
+ flexDirection: 'column',
148
+ rowGap: '8',
149
+ })
150
+
151
+ export const tooltip = style({
152
+ backgroundColor: 'content.primary',
153
+ borderRadius: 'xs',
154
+ color: 'background.primary',
155
+ paddingBlock: '6px !custom',
156
+ paddingInline: '12',
157
+ typography: 'body.b3',
158
+ })
159
+ }
160
+ ```
161
+
162
+ **Don't:** Put links, buttons, or other controls in a tooltip. Use a
163
+ [Popover](/docs/components/popover).
164
+
165
+ ```tsx
166
+ /**
167
+ * Don't example for "Use Tooltips as Labels Only" on the Tooltip page.
168
+ * Don't put links, buttons, or other controls in a tooltip. Use a Popover.
169
+ * @module
170
+ */
171
+ import { Button, style } from '@tempoxyz/ds'
172
+ import { InfoCircle } from '@tempoxyz/ds/icons'
173
+
174
+ /** Renders the static preview, which the guideline card shows inert. */
175
+ export function Demo() {
176
+ return (
177
+ <div {...styles.stack()}>
178
+ <div {...styles.tooltip()}>
179
+ Fees depend on network load. <span {...styles.link()}>Learn more</span>
180
+ </div>
181
+ <Button aria-label="About network fees" shape="icon" size="small" variant="tertiary">
182
+ <InfoCircle />
183
+ </Button>
184
+ </div>
185
+ )
186
+ }
187
+
188
+ namespace styles {
189
+ export const link = style({ textDecorationLine: 'underline !custom' })
190
+
191
+ export const stack = style({
192
+ alignItems: 'center',
193
+ display: 'flex',
194
+ flexDirection: 'column',
195
+ rowGap: '8',
196
+ })
197
+
198
+ export const tooltip = style({
199
+ backgroundColor: 'content.primary',
200
+ borderRadius: 'xs',
201
+ color: 'background.primary',
202
+ maxWidth: '14rem !custom',
203
+ paddingBlock: '6px !custom',
204
+ paddingInline: '12',
205
+ typography: 'body.b3',
206
+ })
207
+ }
208
+ ```
209
+
210
+ ### Keep Essential Information Visible
211
+
212
+ Touch input never opens a tooltip, and screen readers don't announce it. Show amounts, fees, and requirements as text on the page.
213
+
214
+ **Do:** Show the fee and its explanation as visible text.
215
+
216
+ ```tsx
217
+ /**
218
+ * Do example for "Keep Essential Information Visible" on the Tooltip page.
219
+ * Show the fee and its explanation as visible text.
220
+ * @module
221
+ */
222
+ import { style } from '@tempoxyz/ds'
223
+
224
+ /** Renders the static preview, which the guideline card shows inert. */
225
+ export function Demo() {
226
+ return (
227
+ <div {...styles.row()}>
228
+ <div {...styles.text()}>
229
+ <span {...styles.label()}>Network fee</span>
230
+ <span {...styles.hint()}>Paid in the token you send</span>
231
+ </div>
232
+ <span {...styles.value()}>0.001 USDC</span>
233
+ </div>
234
+ )
235
+ }
236
+
237
+ namespace styles {
238
+ export const hint = style({ color: 'content.secondary', typography: 'body.b3' })
239
+
240
+ export const label = style({ color: 'content.primary', typography: 'body.b2Strong' })
241
+
242
+ export const row = style({
243
+ alignItems: 'center',
244
+ columnGap: '24',
245
+ display: 'flex',
246
+ justifyContent: 'space-between',
247
+ width: '16rem !custom',
248
+ })
249
+
250
+ export const text = style({ display: 'flex', flexDirection: 'column', rowGap: '4' })
251
+
252
+ export const value = style({ color: 'content.primary', typography: 'body.b2' })
253
+ }
254
+ ```
255
+
256
+ **Don't:** Hide a value you need to decide behind a tooltip.
257
+
258
+ ```tsx
259
+ /**
260
+ * Don't example for "Keep Essential Information Visible" on the Tooltip page.
261
+ * Don't hide a value you need to decide behind a tooltip.
262
+ * @module
263
+ */
264
+ import { Button, style } from '@tempoxyz/ds'
265
+ import { InfoCircle } from '@tempoxyz/ds/icons'
266
+
267
+ /** Renders the static preview, which the guideline card shows inert. */
268
+ export function Demo() {
269
+ return (
270
+ <div {...styles.stack()}>
271
+ <div {...styles.tooltip()}>0.001 USDC, paid in the token you send</div>
272
+ <div {...styles.row()}>
273
+ <span {...styles.label()}>Network fee</span>
274
+ <Button aria-label="Network fee" shape="icon" size="small" variant="tertiary">
275
+ <InfoCircle />
276
+ </Button>
277
+ </div>
278
+ </div>
279
+ )
280
+ }
281
+
282
+ namespace styles {
283
+ export const label = style({ color: 'content.primary', typography: 'body.b2Strong' })
284
+
285
+ export const row = style({ alignItems: 'center', columnGap: '4', display: 'flex' })
286
+
287
+ export const stack = style({
288
+ alignItems: 'flex-end',
289
+ display: 'flex',
290
+ flexDirection: 'column',
291
+ rowGap: '8',
292
+ })
293
+
294
+ export const tooltip = style({
295
+ backgroundColor: 'content.primary',
296
+ borderRadius: 'xs',
297
+ color: 'background.primary',
298
+ paddingBlock: '6px !custom',
299
+ paddingInline: '12',
300
+ typography: 'body.b3',
301
+ })
302
+ }
303
+ ```
304
+
305
+ ### Group Tooltips With a Provider
306
+
307
+ * **Toolbars (Tooltip.Provider):** Wrap a row of icon buttons, so once one tooltip opens, its neighbors open instantly.
308
+ * **Single Triggers (600ms):** Keep the default `delay`. Shorter delays flash tooltips as the pointer passes.
309
+
310
+ ### Place Tooltips Clear of Related Content
311
+
312
+ `Tooltip.Popup` flips when it would overflow the viewport. Set `side="bottom"` for triggers in a header or top toolbar.
313
+
314
+ **Do:** Choose a side that keeps the value the control acts on visible.
315
+
316
+ ```tsx
317
+ /**
318
+ * Do example for "Place Tooltips Clear of Related Content" on the Tooltip page.
319
+ * Choose a side that keeps the value the control acts on visible.
320
+ * @module
321
+ */
322
+ import { Button, style } from '@tempoxyz/ds'
323
+ import { Refresh } from '@tempoxyz/ds/icons'
324
+
325
+ /** Renders the static preview, which the guideline card shows inert. */
326
+ export function Demo() {
327
+ return (
328
+ <div {...styles.card()}>
329
+ <span {...styles.label()}>Balance</span>
330
+ <div {...styles.row()}>
331
+ <span {...styles.value()}>1,250.00 USDC</span>
332
+ <span {...styles.anchor()}>
333
+ <Button aria-label="Refresh balance" shape="icon" size="small" variant="secondary">
334
+ <Refresh />
335
+ </Button>
336
+ <span {...styles.tooltip()}>Refresh balance</span>
337
+ </span>
338
+ </div>
339
+ </div>
340
+ )
341
+ }
342
+
343
+ namespace styles {
344
+ export const anchor = style({ display: 'flex', position: 'relative' })
345
+
346
+ export const card = style({
347
+ display: 'flex',
348
+ flexDirection: 'column',
349
+ height: '7rem !custom',
350
+ rowGap: '4',
351
+ width: '17rem !custom',
352
+ })
353
+
354
+ export const label = style({ color: 'content.secondary', typography: 'body.b3' })
355
+
356
+ export const row = style({ alignItems: 'center', columnGap: '8', display: 'flex' })
357
+
358
+ // Tooltips render in a portal, so this preview places one with the popup's styles, below the trigger.
359
+ export const tooltip = style({
360
+ backgroundColor: 'content.primary',
361
+ borderRadius: 'xs',
362
+ color: 'background.primary',
363
+ paddingBlock: '6px !custom',
364
+ paddingInline: '12',
365
+ position: 'absolute',
366
+ right: '0',
367
+ top: 'calc(100% + 8px) !custom',
368
+ typography: 'body.b3',
369
+ whiteSpace: 'nowrap',
370
+ })
371
+
372
+ export const value = style({ color: 'content.primary', typography: 'heading.h2' })
373
+ }
374
+ ```
375
+
376
+ **Don't:** Let the tooltip cover the value beside its trigger.
377
+
378
+ ```tsx
379
+ /**
380
+ * Don't example for "Place Tooltips Clear of Related Content" on the Tooltip page.
381
+ * Don't let the tooltip cover the value beside its trigger.
382
+ * @module
383
+ */
384
+ import { Button, style } from '@tempoxyz/ds'
385
+ import { Refresh } from '@tempoxyz/ds/icons'
386
+
387
+ /** Renders the static preview, which the guideline card shows inert. */
388
+ export function Demo() {
389
+ return (
390
+ <div {...styles.card()}>
391
+ <span {...styles.label()}>Balance</span>
392
+ <div {...styles.row()}>
393
+ <span {...styles.value()}>1,250.00 USDC</span>
394
+ <span {...styles.anchor()}>
395
+ <Button aria-label="Refresh balance" shape="icon" size="small" variant="secondary">
396
+ <Refresh />
397
+ </Button>
398
+ <span {...styles.tooltip()}>Refresh balance</span>
399
+ </span>
400
+ </div>
401
+ </div>
402
+ )
403
+ }
404
+
405
+ namespace styles {
406
+ export const anchor = style({ display: 'flex', position: 'relative' })
407
+
408
+ export const card = style({
409
+ display: 'flex',
410
+ flexDirection: 'column',
411
+ height: '7rem !custom',
412
+ rowGap: '4',
413
+ width: '17rem !custom',
414
+ })
415
+
416
+ export const label = style({ color: 'content.secondary', typography: 'body.b3' })
417
+
418
+ export const row = style({ alignItems: 'center', columnGap: '8', display: 'flex' })
419
+
420
+ // Tooltips render in a portal, so this preview places one with the popup's styles, left of the trigger.
421
+ export const tooltip = style({
422
+ backgroundColor: 'content.primary',
423
+ borderRadius: 'xs',
424
+ color: 'background.primary',
425
+ paddingBlock: '6px !custom',
426
+ paddingInline: '12',
427
+ position: 'absolute',
428
+ right: 'calc(100% + 8px) !custom',
429
+ top: '50% !custom',
430
+ transform: 'translateY(-50%) !custom',
431
+ typography: 'body.b3',
432
+ whiteSpace: 'nowrap',
433
+ })
434
+
435
+ export const value = style({ color: 'content.primary', typography: 'heading.h2' })
436
+ }
437
+ ```
438
+
439
+ ## Content
440
+
441
+ ### Write a Few Words
442
+
443
+ Use one to four words. Name the action, such as Refresh balances, not the icon, such as Circular arrows.
444
+
445
+ ## Accessibility
446
+
447
+ A tooltip is visual only, so the trigger needs its own accessible name.
448
+
449
+ ### Semantics
450
+
451
+ * **Tooltip.Trigger (button):** Keeps the role of the element it renders.
452
+ * **Tooltip.Popup:** Has no role and isn't linked to the trigger, so it neither names nor describes it. Mounts only while open.
453
+ * **Contrast (elevated):** Sets primary text on the elevated fill in both schemes.
454
+
455
+ ### Keyboard
456
+
457
+ * **Open on Focus (Tab):** Focus on the trigger opens the tooltip at once.
458
+ * **Close the Tooltip (Escape):** Closes the tooltip while focus stays on the trigger.
459
+
460
+ ### Focus
461
+
462
+ * **No Focus:** The tooltip never takes focus and holds no interactive content.
463
+ * **Pointer:** Opens after 600ms of hover. The pointer can move onto the popup without closing it.
464
+ * **Touch:** Touch input never opens it, so no task may depend on one.
465
+
466
+ ### Your Responsibilities
467
+
468
+ * **Name Icon-Only Triggers (aria-label):** Name an icon-only trigger with the tooltip text.
469
+
470
+ ## Related
471
+
472
+ [Popover](/docs/components/popover)
473
+
474
+ Use for info icons and interactive content.
475
+
476
+ [Button](/docs/components/button)
477
+
478
+ Use for icon-only buttons.
479
+
480
+ [CopyButton](/docs/components/copy-button)
481
+
482
+ Use for a copy action that names itself.
483
+
484
+ [Field](/docs/components/field)
485
+
486
+ Use for descriptions that stay visible.
487
+
488
+ [Dashboards](/docs/patterns/dashboards)
489
+
490
+ Covers metric explanations.
@@ -0,0 +1,116 @@
1
+ # VerificationCode
2
+
3
+ Shows a code that a person compares with the one another app shows.
4
+
5
+ [View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/VerificationCode.tsx)
6
+
7
+ Figma: [Content/Verification Code](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=5227-3952) (`VerificationCode.Root`)
8
+
9
+ ## Overview
10
+
11
+ A verification code renders a centered box with a label above a large code. A person reads the code and checks that it matches the code on another device or app, such as in a device sign-in.
12
+
13
+ ## Examples
14
+
15
+ ### Basic
16
+
17
+ ```tsx
18
+ import { VerificationCode } from '@tempoxyz/ds'
19
+
20
+ export function Demo() {
21
+ return (
22
+ <VerificationCode.Root>
23
+ <VerificationCode.Label>Confirm this code matches Claude</VerificationCode.Label>
24
+ <VerificationCode.Value>WXYZ-4821</VerificationCode.Value>
25
+ </VerificationCode.Root>
26
+ )
27
+ }
28
+ ```
29
+
30
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/VerificationCode/Basic.tsx)
31
+
32
+ ## Anatomy
33
+
34
+ Import the component and assemble its parts.
35
+
36
+ ```tsx
37
+ import { VerificationCode } from '@tempoxyz/ds'
38
+
39
+ <VerificationCode.Root>
40
+ <VerificationCode.Label />
41
+ <VerificationCode.Value />
42
+ </VerificationCode.Root>
43
+ ```
44
+
45
+ ## Guidelines
46
+
47
+ ### When to Use
48
+
49
+ * Confirm a device sign-in by matching the code that an app or a terminal shows.
50
+ * Pair two devices by a code that both show.
51
+
52
+ ### When Not to Use
53
+
54
+ * Use [OtpField](/docs/components/otp-field) when the person types a code.
55
+ * Use [Snippet](/docs/components/snippet) for a command or a value to copy.
56
+
57
+ ### Match the Other Device
58
+
59
+ **Do:** Name the app that shows the code, and keep its grouping.
60
+
61
+ ```tsx
62
+ import { VerificationCode } from '@tempoxyz/ds'
63
+
64
+ export function Demo() {
65
+ return (
66
+ <VerificationCode.Root>
67
+ <VerificationCode.Label>Confirm this code matches Claude</VerificationCode.Label>
68
+ <VerificationCode.Value>WXYZ-4821</VerificationCode.Value>
69
+ </VerificationCode.Root>
70
+ )
71
+ }
72
+ ```
73
+
74
+ **Don't:** Regroup the code, or leave out where it comes from.
75
+
76
+ ```tsx
77
+ import { VerificationCode } from '@tempoxyz/ds'
78
+
79
+ export function Demo() {
80
+ return (
81
+ <VerificationCode.Root>
82
+ <VerificationCode.Label>Your code</VerificationCode.Label>
83
+ <VerificationCode.Value>WX YZ 48 21</VerificationCode.Value>
84
+ </VerificationCode.Root>
85
+ )
86
+ }
87
+ ```
88
+
89
+ ## Content
90
+
91
+ ### Write the Label
92
+
93
+ Start the label with the action, such as Confirm this code matches Claude. Name the app or device that shows the other code.
94
+
95
+ ## Accessibility
96
+
97
+ A verification code renders a `<div>` with the label in a `<p>` and the code in a `<span>`. Screen readers read the label, then the code.
98
+
99
+ ### Semantics
100
+
101
+ * **Label (p):** Screen readers read the label before the code.
102
+ * **Value (translate=no):** Browsers do not translate the code, and a click selects all of it.
103
+
104
+ ### Your Responsibilities
105
+
106
+ * **Keep the Code on Screen (SC 3.3.8):** Show the code until the sign-in finishes, so people can compare it.
107
+
108
+ ## Related
109
+
110
+ [OtpField](/docs/components/otp-field)
111
+
112
+ Use for a code that a person types.
113
+
114
+ [Snippet](/docs/components/snippet)
115
+
116
+ Use for a command or a value to copy.