@tempoxyz/ds 0.3.9 → 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 (128) 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/dist/web/components/OtpField.css +1 -1
  121. package/dist/web/components/OtpField.d.ts +1 -1
  122. package/dist/web/components/OtpField.d.ts.map +1 -1
  123. package/dist/web/components/OtpField.js +3 -4
  124. package/dist/web/components/OtpField.js.map +1 -1
  125. package/dist/web/components/OtpField.js.zyzz.json +1 -1
  126. package/dist/web/index.js.zyzz.json +1 -1
  127. package/package.json +1 -1
  128. package/src/web/components/OtpField.tsx +2 -24
@@ -0,0 +1,321 @@
1
+ # Avatar
2
+
3
+ Represents a person, contact, or wallet with an image, initials, or an icon.
4
+
5
+ [View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/Avatar.tsx)
6
+
7
+ Figma: [Avatar](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=1418-13100)
8
+
9
+ ## Overview
10
+
11
+ An avatar is a circle that holds an image, or initials or an icon in secondary text on a neutral fill. It leads a list row or a modal header.
12
+
13
+ ## Examples
14
+
15
+ ### Basic
16
+
17
+ ```tsx
18
+ import { Avatar } from '@tempoxyz/ds'
19
+
20
+ export function Demo() {
21
+ return (
22
+ <Avatar.Root>
23
+ <Avatar.Fallback>J</Avatar.Fallback>
24
+ </Avatar.Root>
25
+ )
26
+ }
27
+ ```
28
+
29
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Avatar/Basic.tsx)
30
+
31
+ ### Size
32
+
33
+ Set `size` to `16`, `24`, `32`, `40` (default), `48`, or `64`.
34
+
35
+ ```tsx
36
+ import { Avatar, style } from '@tempoxyz/ds'
37
+
38
+ export function Demo() {
39
+ return (
40
+ <div {...styles.row()}>
41
+ {(['16', '24', '32', '40', '48', '64'] as const).map((size) => (
42
+ <Avatar.Root key={size} size={size}>
43
+ <Avatar.Fallback>J</Avatar.Fallback>
44
+ </Avatar.Root>
45
+ ))}
46
+ </div>
47
+ )
48
+ }
49
+
50
+ namespace styles {
51
+ export const row = style({ alignItems: 'center', display: 'flex', gap: '12' })
52
+ }
53
+ ```
54
+
55
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Avatar/Size.tsx)
56
+
57
+ ### Icon
58
+
59
+ Put an icon in `Avatar.Fallback` for a wallet or app. It renders at 16px in a `24` or `32` avatar, and at 20px in a `40` avatar.
60
+
61
+ ```tsx
62
+ import { Avatar, style } from '@tempoxyz/ds'
63
+ import { Wallet } from '@tempoxyz/ds/icons'
64
+
65
+ export function Demo() {
66
+ return (
67
+ <div {...styles.row()}>
68
+ {(['24', '32', '40'] as const).map((size) => (
69
+ <Avatar.Root key={size} size={size}>
70
+ <Avatar.Fallback>
71
+ <Wallet />
72
+ </Avatar.Fallback>
73
+ </Avatar.Root>
74
+ ))}
75
+ </div>
76
+ )
77
+ }
78
+
79
+ namespace styles {
80
+ export const row = style({ alignItems: 'center', display: 'flex', gap: '12' })
81
+ }
82
+ ```
83
+
84
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Avatar/Icon.tsx)
85
+
86
+ ## Anatomy
87
+
88
+ Import the component and assemble its parts.
89
+
90
+ ```tsx
91
+ import { Avatar } from '@tempoxyz/ds'
92
+
93
+ <Avatar />
94
+
95
+ <Avatar.Root>
96
+ <Avatar.Image />
97
+ <Avatar.Fallback />
98
+ </Avatar.Root>
99
+ ```
100
+
101
+ ## Guidelines
102
+
103
+ ### When to Use
104
+
105
+ * Represent a person or organization beside their name, such as a contact in Send or a merchant in activity.
106
+ * Represent a wallet or app with an icon, such as a connected wallet in a list row.
107
+
108
+ ### When Not to Use
109
+
110
+ * Use [Identicon](/docs/components/identicon) for an account known only by its address.
111
+ * Use [TokenLogo](/docs/components/token-logo) for the icon of a token or asset.
112
+ * Use [IconTile](/docs/components/icon-tile) for the icon above a centered modal title.
113
+
114
+ ### Choose Avatar or Identicon
115
+
116
+ * **Person or Organization (Avatar):** A name, shown as initials.
117
+ * **Address Only (Identicon):** An account known only by its address.
118
+ * **Mixed List (Avatar.Fallback):** A mix of both, with an identicon in the fallback.
119
+
120
+ ### Always Include a Fallback
121
+
122
+ * **People and organizations:** Use initials.
123
+ * **Wallets and apps:** Use an icon.
124
+ * **Accounts known by address:** Use an [Identicon](/docs/components/identicon) with `size="fill"`.
125
+
126
+ **Do:** Give every avatar a fallback, such as initials, an icon, or an `Identicon`.
127
+
128
+ ```tsx
129
+ /**
130
+ * Do example for "Always Include a Fallback" on the Avatar page.
131
+ * Give every avatar a fallback, such as initials, an icon, or an `Identicon`.
132
+ * @module
133
+ */
134
+ import { Avatar, Identicon, style } from '@tempoxyz/ds'
135
+ import { Wallet } from '@tempoxyz/ds/icons'
136
+
137
+ /** Renders the static preview, which the guideline card shows inert. */
138
+ export function Demo() {
139
+ return (
140
+ <div {...styles.row()}>
141
+ <Avatar size="40">
142
+ <Avatar.Fallback>AL</Avatar.Fallback>
143
+ </Avatar>
144
+ <Avatar size="40">
145
+ <Avatar.Fallback>
146
+ <Wallet />
147
+ </Avatar.Fallback>
148
+ </Avatar>
149
+ <Avatar size="40">
150
+ <Avatar.Fallback>
151
+ <Identicon address="0x71C7656EC7ab88b098defB751B7401B5f6d8976F" aria-hidden size="fill" />
152
+ </Avatar.Fallback>
153
+ </Avatar>
154
+ </div>
155
+ )
156
+ }
157
+
158
+ namespace styles {
159
+ export const row = style({ alignItems: 'center', display: 'flex', gap: '12' })
160
+ }
161
+ ```
162
+
163
+ **Don't:** Leave an empty circle.
164
+
165
+ ```tsx
166
+ /**
167
+ * Don't example for "Always Include a Fallback" on the Avatar page.
168
+ * Don't leave an empty circle.
169
+ * @module
170
+ */
171
+ import { Avatar, style } from '@tempoxyz/ds'
172
+
173
+ /** Renders the static preview, which the guideline card shows inert. */
174
+ export function Demo() {
175
+ return (
176
+ <div {...styles.row()}>
177
+ <Avatar size="40" />
178
+ <Avatar size="40" />
179
+ <Avatar size="40" />
180
+ </div>
181
+ )
182
+ }
183
+
184
+ namespace styles {
185
+ export const row = style({ alignItems: 'center', display: 'flex', gap: '12' })
186
+ }
187
+ ```
188
+
189
+ ### Pair the Avatar With a Name
190
+
191
+ Hide the avatar with `aria-hidden` beside a visible name, so screen readers don't read the initials and the name.
192
+
193
+ **Do:** Show the name, and a detail such as an email, beside each avatar.
194
+
195
+ ```tsx
196
+ /**
197
+ * Do example for "Pair the Avatar With a Name" on the Avatar page.
198
+ * Show the name, and a detail such as an email, beside each avatar.
199
+ * @module
200
+ */
201
+ import { Avatar, style } from '@tempoxyz/ds'
202
+
203
+ const contacts = [
204
+ ['JC', 'Jane Cooper', 'jane@example.com'],
205
+ ['AL', 'Ada Lovelace', 'ada@example.com'],
206
+ ] as const
207
+
208
+ /** Renders the static preview, which the guideline card shows inert. */
209
+ export function Demo() {
210
+ return (
211
+ <div {...styles.list()}>
212
+ {contacts.map(([initials, name, email]) => (
213
+ <div key={name} {...styles.row()}>
214
+ <Avatar aria-hidden size="40">
215
+ <Avatar.Fallback>{initials}</Avatar.Fallback>
216
+ </Avatar>
217
+ <div {...styles.text()}>
218
+ <span {...styles.name()}>{name}</span>
219
+ <span {...styles.detail()}>{email}</span>
220
+ </div>
221
+ </div>
222
+ ))}
223
+ </div>
224
+ )
225
+ }
226
+
227
+ namespace styles {
228
+ export const detail = style({ color: 'content.secondary', typography: 'body.b3' })
229
+
230
+ export const list = style({ display: 'grid', gap: '12', width: '100% !custom' })
231
+
232
+ export const name = style({ color: 'content.primary', typography: 'body.b2Strong' })
233
+
234
+ export const row = style({ alignItems: 'center', display: 'flex', gap: '12' })
235
+
236
+ export const text = style({ display: 'flex', flexDirection: 'column', gap: '4' })
237
+ }
238
+ ```
239
+
240
+ **Don't:** Ask people to pick a recipient from initials alone.
241
+
242
+ ```tsx
243
+ /**
244
+ * Don't example for "Pair the Avatar With a Name" on the Avatar page.
245
+ * Don't ask people to pick a recipient from pictures or initials alone.
246
+ * @module
247
+ */
248
+ import { Avatar, style } from '@tempoxyz/ds'
249
+
250
+ /** Renders the static preview, which the guideline card shows inert. */
251
+ export function Demo() {
252
+ return (
253
+ <div {...styles.row()}>
254
+ {['JC', 'AL', 'MR', 'JD'].map((initials) => (
255
+ <Avatar key={initials} size="40">
256
+ <Avatar.Fallback>{initials}</Avatar.Fallback>
257
+ </Avatar>
258
+ ))}
259
+ </div>
260
+ )
261
+ }
262
+
263
+ namespace styles {
264
+ export const row = style({ alignItems: 'center', display: 'flex', gap: '12' })
265
+ }
266
+ ```
267
+
268
+ ### Match Size to the Layout
269
+
270
+ * **Inline and Dense Rows (24):** Inline with text and in dense table rows.
271
+ * **List Rows (32):** List rows, such as recipients in a modal.
272
+ * **Header Lead (40):** The default. The lead of a header.
273
+
274
+ ### Use Initials for People and Icons for Wallets
275
+
276
+ * **Person or Contact (Initials):** One or two initials from the name.
277
+ * **Wallet or App (Icon):** One icon from the library, in the text color.
278
+
279
+ In a modal, leave out brand colors, so every avatar keeps the neutral fill.
280
+
281
+ ## Content
282
+
283
+ * **Initials:** Use one or two, such as AL for Ada Lovelace. The fallback uppercases them.
284
+ * **Organizations:** Use the first letter of the name, not an unfamiliar abbreviation.
285
+ * **Wallets and apps:** Use an icon instead of letters.
286
+
287
+ ## Accessibility
288
+
289
+ Renders a `<span>` that holds the fallback.
290
+
291
+ ### Semantics
292
+
293
+ * **Avatar.Fallback (span):** Plain text. Screen readers read the initials as written.
294
+ * **Icon Fallback (aria-hidden):** Icons without an `aria-label` are hidden, so the avatar is silent.
295
+
296
+ ### Keyboard
297
+
298
+ An avatar takes no focus. To open a profile, wrap the avatar and name in one link, and let the name label it.
299
+
300
+ ### Your Responsibilities
301
+
302
+ * **Hide a Duplicate Avatar (aria-hidden):** If the name is visible beside the avatar, hide the root so screen readers skip the initials.
303
+ * **Name a Standalone Avatar (aria-label):** If no name is visible, set `role="img"` and an `aria-label` with the full name on the root.
304
+
305
+ ## Related
306
+
307
+ [Identicon](/docs/components/identicon)
308
+
309
+ Use for accounts known by address.
310
+
311
+ [TokenLogo](/docs/components/token-logo)
312
+
313
+ Use for token icons.
314
+
315
+ [IconTile](/docs/components/icon-tile)
316
+
317
+ Use for the icon above a centered modal title.
318
+
319
+ [ListGroup](/docs/components/list-group)
320
+
321
+ Use for lists of people and accounts.
@@ -0,0 +1,339 @@
1
+ # Badge
2
+
3
+ Labels a status or category in a compact chip.
4
+
5
+ [View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/Badge.tsx)
6
+
7
+ Figma: [Badge](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=1186-3286), [Icon Badge](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=1191-4539)
8
+
9
+ ## Overview
10
+
11
+ A compact chip at least 80px wide, in one of five `variant` fills and two sizes, or a square or round chip that holds one icon. It renders a `<span>` unless you pass `render`.
12
+
13
+ ## Examples
14
+
15
+ ### Basic
16
+
17
+ ```tsx
18
+ import { Badge } from '@tempoxyz/ds'
19
+
20
+ export function Demo() {
21
+ return <Badge>Routes</Badge>
22
+ }
23
+ ```
24
+
25
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Badge/Basic.tsx)
26
+
27
+ ### Variant
28
+
29
+ Set `variant` to `soft` (default), `outlined`, `elevated`, `inverse`, or `accent`.
30
+
31
+ ```tsx
32
+ import { Badge, style } from '@tempoxyz/ds'
33
+
34
+ export function Demo() {
35
+ return (
36
+ <div {...styles.row()}>
37
+ <Badge>Routes</Badge>
38
+ <Badge variant="outlined">Testnet</Badge>
39
+ <Badge variant="elevated">New</Badge>
40
+ <Badge variant="inverse">Recommended</Badge>
41
+ <Badge variant="accent">Beta</Badge>
42
+ </div>
43
+ )
44
+ }
45
+
46
+ namespace styles {
47
+ export const row = style({
48
+ alignItems: 'center',
49
+ backgroundColor: 'container.regular',
50
+ borderRadius: 'xs',
51
+ display: 'flex',
52
+ flexWrap: 'wrap',
53
+ gap: '8',
54
+ padding: '16',
55
+ })
56
+ }
57
+ ```
58
+
59
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Badge/Variant.tsx)
60
+
61
+ ### Size
62
+
63
+ Set `size` to `small` (28px) or `medium` (32px, the default).
64
+
65
+ ```tsx
66
+ import { Badge, style } from '@tempoxyz/ds'
67
+
68
+ export function Demo() {
69
+ return (
70
+ <div {...styles.row()}>
71
+ {(['small', 'medium'] as const).map((size) => (
72
+ <Badge key={size} size={size}>
73
+ {size}
74
+ </Badge>
75
+ ))}
76
+ </div>
77
+ )
78
+ }
79
+
80
+ namespace styles {
81
+ export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '8' })
82
+ }
83
+ ```
84
+
85
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Badge/Size.tsx)
86
+
87
+ ### Shape
88
+
89
+ Set `shape="icon"` for a badge that holds one icon. A `medium` icon badge is a 32px square, and a `small` one is a 24px circle.
90
+
91
+ ```tsx
92
+ import { Badge, style } from '@tempoxyz/ds'
93
+ import { ArrowRight } from '@tempoxyz/ds/icons'
94
+
95
+ export function Demo() {
96
+ return (
97
+ <div {...styles.rows()}>
98
+ {(['medium', 'small'] as const).map((size) => (
99
+ <div key={size} {...styles.row()}>
100
+ {(['soft', 'outlined', 'elevated', 'inverse', 'accent'] as const).map((variant) => (
101
+ <Badge key={variant} shape="icon" size={size} variant={variant}>
102
+ <ArrowRight />
103
+ </Badge>
104
+ ))}
105
+ </div>
106
+ ))}
107
+ </div>
108
+ )
109
+ }
110
+
111
+ namespace styles {
112
+ export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '8' })
113
+
114
+ export const rows = style({ display: 'grid', gap: '12' })
115
+ }
116
+ ```
117
+
118
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Badge/Shape.tsx)
119
+
120
+ ### Render
121
+
122
+ Pass a `button` or link to `render` for an interactive badge with pointer, focus, and press feedback.
123
+
124
+ ```tsx
125
+ import { Badge, style } from '@tempoxyz/ds'
126
+
127
+ export function Demo() {
128
+ return (
129
+ <div {...styles.row()}>
130
+ {(['small', 'medium'] as const).map((size) => (
131
+ <Badge key={size} render={<button type="button" />} size={size}>
132
+ Stablecoins
133
+ </Badge>
134
+ ))}
135
+ <Badge render={<button type="button" />} variant="accent">
136
+ Accent chip
137
+ </Badge>
138
+ </div>
139
+ )
140
+ }
141
+
142
+ namespace styles {
143
+ export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '8' })
144
+ }
145
+ ```
146
+
147
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Badge/Render.tsx)
148
+
149
+ ## Anatomy
150
+
151
+ Import the component and assemble its parts.
152
+
153
+ ```tsx
154
+ import { Badge } from '@tempoxyz/ds'
155
+
156
+ <Badge />
157
+ ```
158
+
159
+ ## Guidelines
160
+
161
+ ### When to Use
162
+
163
+ * Label an attribute next to a title or row value, such as Routes, New address, or Testnet.
164
+ * Label the status of a record in words, such as Confirmed, Pending, or Failed.
165
+ * Build compact filters, such as Stablecoins, with `render={<button type="button" />}`.
166
+
167
+ ### When Not to Use
168
+
169
+ * Use an [Alert](/docs/components/alert) or [Banner](/docs/components/banner) for a message that needs a sentence.
170
+ * Use a [Button](/docs/components/button) for an action, such as Retry.
171
+ * Use the `status` of a [Table](/docs/components/table) cell to color a status in a table.
172
+ * Use a [ChoiceGroup](/docs/components/choice-group) to switch between two to four views.
173
+ * Use [Kbd](/docs/components/kbd) for keyboard keys.
174
+
175
+ ### Choose a Variant by Emphasis
176
+
177
+ * **Soft (soft):** The default. Attributes and categories on any surface.
178
+ * **Outlined (outlined):** Lower emphasis, such as a network beside its name.
179
+ * **Elevated (elevated):** A white fill that stands out on a tinted surface.
180
+ * **Inverse (inverse):** The strongest fill, for one recommended option.
181
+ * **Accent (accent):** Something new or highlighted, such as Beta.
182
+
183
+ ### Keep One Variant per Context
184
+
185
+ Use one variant for every badge in a list or column, so only the label differs.
186
+
187
+ **Do:** Keep one variant per list or column, so only the status differs.
188
+
189
+ ```tsx
190
+ /**
191
+ * Do example for "Keep One Variant per Context" on the Badge page.
192
+ * Keep one variant per list or column, so only the status differs.
193
+ * @module
194
+ */
195
+ import { Badge, style } from '@tempoxyz/ds'
196
+
197
+ const payments = [
198
+ { address: '0x8f3c…a21b', status: 'Confirmed', variant: 'outlined' },
199
+ { address: '0x41d0…9c7e', status: 'Pending', variant: 'outlined' },
200
+ { address: '0xb27a…04f5', status: 'Failed', variant: 'outlined' },
201
+ ] as const
202
+
203
+ /** Renders the static preview, which the guideline card shows inert. */
204
+ export function Demo() {
205
+ return (
206
+ <div {...styles.list()}>
207
+ {payments.map((payment) => (
208
+ <div {...styles.row()} key={payment.address}>
209
+ <span>{payment.address}</span>
210
+ <Badge size="small" variant={payment.variant}>
211
+ {payment.status}
212
+ </Badge>
213
+ </div>
214
+ ))}
215
+ </div>
216
+ )
217
+ }
218
+
219
+ namespace styles {
220
+ export const list = style({
221
+ display: 'flex',
222
+ flexDirection: 'column',
223
+ gap: '12',
224
+ width: '100% !custom',
225
+ })
226
+
227
+ export const row = style({
228
+ alignItems: 'center',
229
+ display: 'flex',
230
+ justifyContent: 'space-between',
231
+ typography: 'mono.m1',
232
+ })
233
+ }
234
+ ```
235
+
236
+ **Don't:** Mix `soft`, `outlined`, and `inverse` badges in one list.
237
+
238
+ ```tsx
239
+ /**
240
+ * Don't example for "Keep One Variant per Context" on the Badge page.
241
+ * Don't mix `soft`, `outlined`, and `inverse` tags in one list.
242
+ * @module
243
+ */
244
+ import { Badge, style } from '@tempoxyz/ds'
245
+
246
+ const payments = [
247
+ { address: '0x8f3c…a21b', status: 'Confirmed', variant: 'soft' },
248
+ { address: '0x41d0…9c7e', status: 'Pending', variant: 'outlined' },
249
+ { address: '0xb27a…04f5', status: 'Failed', variant: 'inverse' },
250
+ ] as const
251
+
252
+ /** Renders the static preview, which the guideline card shows inert. */
253
+ export function Demo() {
254
+ return (
255
+ <div {...styles.list()}>
256
+ {payments.map((payment) => (
257
+ <div {...styles.row()} key={payment.address}>
258
+ <span>{payment.address}</span>
259
+ <Badge size="small" variant={payment.variant}>
260
+ {payment.status}
261
+ </Badge>
262
+ </div>
263
+ ))}
264
+ </div>
265
+ )
266
+ }
267
+
268
+ namespace styles {
269
+ export const list = style({
270
+ display: 'flex',
271
+ flexDirection: 'column',
272
+ gap: '12',
273
+ width: '100% !custom',
274
+ })
275
+
276
+ export const row = style({
277
+ alignItems: 'center',
278
+ display: 'flex',
279
+ justifyContent: 'space-between',
280
+ typography: 'mono.m1',
281
+ })
282
+ }
283
+ ```
284
+
285
+ ### Make a Badge Interactive Only for an Action
286
+
287
+ * **Display (span):** A status or attribute. Keep the default `span`.
288
+ * **Action (render):** Pass a button or link only if the badge does something.
289
+
290
+ ## Content
291
+
292
+ * Keep the text to one or two words in sentence case, such as Expiring soon.
293
+ * Describe a state, not an action. Write Failed, not Retry.
294
+ * Use one word for one state across a product, such as Confirmed everywhere, not Confirmed in one place and Complete in another.
295
+ * Tags don't wrap, so a long label overflows its cell.
296
+
297
+ ## Accessibility
298
+
299
+ A badge renders a `<span>` with no role, so screen readers read its text inline.
300
+
301
+ ### Semantics
302
+
303
+ * **Root (span):** Screen readers read its text in place, as part of the surrounding content.
304
+ * **Render (render):** Takes the semantics of the button or link you pass, with a focus outline and press scale.
305
+ * **Variant (variant):** Changes only the fill, sets no state or role, and isn't announced. The text must name it.
306
+
307
+ ### Keyboard
308
+
309
+ A static badge takes no focus. A badge rendered as a button or link is a native control:
310
+
311
+ * **Move Focus to the Badge (Tab):** Moves focus to the badge.
312
+ * **Activate or Follow (Enter):** Activates a button badge or follows a link badge.
313
+ * **Activate a Button Badge (Space):** Activates a button badge.
314
+
315
+ ### Your Responsibilities
316
+
317
+ * **Name Meaningful Icons (aria-label):** If an icon badge carries meaning, set `role="img"` and an `aria-label` that names it.
318
+ * **Use Native Controls (button or a):** Pass a native button or link to `render`, so keyboards reach it. Don't add `onClick` to a static span.
319
+ * **Add Context (aria-describedby):** If a badge sits apart from its subject, add context, so "Pending" isn't read alone.
320
+ * **Report Toggle State (aria-pressed):** A filter badge must report whether it is pressed, so its state is announced.
321
+ * **Size Interactive Badges (24px):** Both sizes clear the 24px minimum target. Use medium where people tap.
322
+
323
+ ## Related
324
+
325
+ [Table](/docs/components/table)
326
+
327
+ Use for status columns.
328
+
329
+ [Alert](/docs/components/alert)
330
+
331
+ Use for messages about a section.
332
+
333
+ [ChoiceGroup](/docs/components/choice-group)
334
+
335
+ Use for switching views.
336
+
337
+ [Feedback and Status](/docs/patterns/feedback-and-status)
338
+
339
+ Covers status conventions.