@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,627 @@
1
+ # Tabs
2
+
3
+ Switches between related views.
4
+
5
+ [View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/Tabs.tsx)
6
+
7
+ Figma: [Controls/Tab](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=5227-3285) (`Tabs.Tab`), [Tab](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=1186-3208) (`Tabs.Tab`)
8
+
9
+ ## Overview
10
+
11
+ Tabs render an underlined or pill tab list over a set of panels. Use them for related content, and use links for page navigation.
12
+
13
+ ## Examples
14
+
15
+ ### Basic
16
+
17
+ ```tsx
18
+ import { Tabs } from '@tempoxyz/ds'
19
+
20
+ export function Demo() {
21
+ return (
22
+ <Tabs.Root defaultValue="overview">
23
+ <Tabs.List aria-label="Sections">
24
+ <Tabs.Tab value="overview">Overview</Tabs.Tab>
25
+ <Tabs.Tab value="activity">Activity</Tabs.Tab>
26
+ <Tabs.Tab value="settings">Settings</Tabs.Tab>
27
+ <Tabs.Indicator />
28
+ </Tabs.List>
29
+ <Tabs.Panel value="overview">Overview content</Tabs.Panel>
30
+ <Tabs.Panel value="activity">Activity content</Tabs.Panel>
31
+ <Tabs.Panel value="settings">Settings content</Tabs.Panel>
32
+ </Tabs.Root>
33
+ )
34
+ }
35
+ ```
36
+
37
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Tabs/Basic.tsx)
38
+
39
+ ### Size
40
+
41
+ Set `size` on `Tabs.List` to `small`, `medium` (default), or `large`, for 32px, 40px, or 56px tabs.
42
+
43
+ ```tsx
44
+ import { Stack, Tabs } from '@tempoxyz/ds'
45
+ import { Plus } from '@tempoxyz/ds/icons'
46
+
47
+ export function Demo() {
48
+ return (
49
+ <Stack align="start" gap="24">
50
+ {(['small', 'medium', 'large'] as const).map((size) => (
51
+ <Tabs.Root defaultValue="overview" key={size}>
52
+ <Tabs.List aria-label={`Sections ${size}`} size={size}>
53
+ <Tabs.Tab value="overview">Overview</Tabs.Tab>
54
+ <Tabs.Tab value="activity">
55
+ <Plus />
56
+ Activity
57
+ </Tabs.Tab>
58
+ <Tabs.Tab disabled value="settings">
59
+ Settings
60
+ </Tabs.Tab>
61
+ <Tabs.Indicator />
62
+ </Tabs.List>
63
+ <Tabs.Panel value="overview">Overview content</Tabs.Panel>
64
+ <Tabs.Panel value="activity">Activity content</Tabs.Panel>
65
+ </Tabs.Root>
66
+ ))}
67
+ </Stack>
68
+ )
69
+ }
70
+ ```
71
+
72
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Tabs/Size.tsx)
73
+
74
+ ### Disabled
75
+
76
+ Set `disabled` on a `Tabs.Tab` to skip it during selection.
77
+
78
+ ```tsx
79
+ import { Tabs } from '@tempoxyz/ds'
80
+
81
+ export function Demo() {
82
+ return (
83
+ <Tabs.Root defaultValue="overview">
84
+ <Tabs.List aria-label="Sections">
85
+ <Tabs.Tab value="overview">Overview</Tabs.Tab>
86
+ <Tabs.Tab value="activity">Activity</Tabs.Tab>
87
+ <Tabs.Tab disabled value="settings">
88
+ Settings
89
+ </Tabs.Tab>
90
+ <Tabs.Indicator />
91
+ </Tabs.List>
92
+ <Tabs.Panel value="overview">Overview content</Tabs.Panel>
93
+ <Tabs.Panel value="activity">Activity content</Tabs.Panel>
94
+ </Tabs.Root>
95
+ )
96
+ }
97
+ ```
98
+
99
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Tabs/Disabled.tsx)
100
+
101
+ ### Expand
102
+
103
+ Set `expand` on `Tabs.List` to stretch the tabs across the available width.
104
+
105
+ ```tsx
106
+ import { Tabs } from '@tempoxyz/ds'
107
+
108
+ export function Demo() {
109
+ return (
110
+ <Tabs.Root defaultValue="activity" style={{ width: '20rem' }}>
111
+ <Tabs.List aria-label="Account" expand>
112
+ <Tabs.Tab value="activity">Activity</Tabs.Tab>
113
+ <Tabs.Tab value="assets">Assets</Tabs.Tab>
114
+ <Tabs.Tab value="keys">Keys</Tabs.Tab>
115
+ <Tabs.Indicator />
116
+ </Tabs.List>
117
+ </Tabs.Root>
118
+ )
119
+ }
120
+ ```
121
+
122
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Tabs/Expand.tsx)
123
+
124
+ ### Pill
125
+
126
+ Set `variant="pill"` on `Tabs.List` for filled tabs. The fill marks the active tab, so a pill list takes no `Tabs.Indicator`. Pill tabs are 32px, 40px, or 48px tall.
127
+
128
+ ```tsx
129
+ import { Stack, Tabs } from '@tempoxyz/ds'
130
+
131
+ export function Demo() {
132
+ return (
133
+ <Stack align="start" gap="24">
134
+ {(['small', 'medium', 'large'] as const).map((size) => (
135
+ <Tabs.Root defaultValue="all" key={size}>
136
+ <Tabs.List aria-label={`Transfers ${size}`} size={size} variant="pill">
137
+ <Tabs.Tab value="all">All</Tabs.Tab>
138
+ <Tabs.Tab value="payments">Payments</Tabs.Tab>
139
+ <Tabs.Tab value="payouts">Payouts</Tabs.Tab>
140
+ </Tabs.List>
141
+ </Tabs.Root>
142
+ ))}
143
+ </Stack>
144
+ )
145
+ }
146
+ ```
147
+
148
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Tabs/Pill.tsx)
149
+
150
+ ### Appearance
151
+
152
+ Set `appearance` on a pill `Tabs.List` to `base` (default) on the page, `inverse` on an inverse surface, or `overlay` over an image or video.
153
+
154
+ ```tsx
155
+ import { Stack, Tabs, variants } from '@tempoxyz/ds'
156
+
157
+ export function Demo() {
158
+ return (
159
+ <Stack gap="16">
160
+ {(['base', 'inverse', 'overlay'] as const).map((appearance) => (
161
+ <div key={appearance} {...styles.surface({ appearance })}>
162
+ <Tabs.Root defaultValue="all">
163
+ <Tabs.List
164
+ appearance={appearance}
165
+ aria-label={`Transfers ${appearance}`}
166
+ variant="pill"
167
+ >
168
+ <Tabs.Tab value="all">All</Tabs.Tab>
169
+ <Tabs.Tab value="payments">Payments</Tabs.Tab>
170
+ <Tabs.Tab value="payouts">Payouts</Tabs.Tab>
171
+ </Tabs.List>
172
+ </Tabs.Root>
173
+ </div>
174
+ ))}
175
+ </Stack>
176
+ )
177
+ }
178
+
179
+ namespace styles {
180
+ export const surface = variants({
181
+ base: { borderRadius: 'sm', padding: '16' },
182
+ variants: {
183
+ appearance: {
184
+ base: { backgroundColor: 'background.primary' },
185
+ inverse: { backgroundColor: 'inverse.background.primary' },
186
+ overlay: {
187
+ backgroundImage: 'linear-gradient(135deg, #4471ed, #7e59e4) !custom',
188
+ },
189
+ },
190
+ },
191
+ })
192
+ }
193
+ ```
194
+
195
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Tabs/Appearance.tsx)
196
+
197
+ ## Anatomy
198
+
199
+ Import the component and assemble its parts.
200
+
201
+ ```tsx
202
+ import { Tabs } from '@tempoxyz/ds'
203
+
204
+ <Tabs.Root>
205
+ <Tabs.List>
206
+ <Tabs.Tab />
207
+ <Tabs.Indicator />
208
+ </Tabs.List>
209
+ <Tabs.Panel />
210
+ </Tabs.Root>
211
+ ```
212
+
213
+ ## Guidelines
214
+
215
+ ### When to Use
216
+
217
+ * Switch between views of one subject at the same level, such as a webhook's Overview, Deliveries, and Settings.
218
+ * Split a dense page into parts used one at a time, such as Balances and Activity on a wallet's home screen.
219
+
220
+ ### When Not to Use
221
+
222
+ * Use [ChoiceGroup](/docs/components/choice-group) to pick a value that changes the current view, such as a chart's 1D, 1W, or 1M range.
223
+ * Use [SidebarMenu](/docs/components/sidebar-menu) or links to move between pages with their own URLs.
224
+ * Use [Stepper](/docs/components/stepper) for steps completed in order.
225
+ * Use [Accordion](/docs/components/accordion) to open several sections at once, or to compare them.
226
+
227
+ ### Keep Tabs Few and Short
228
+
229
+ Use two to five tabs with one-word or two-word labels. Overflowing tabs scroll sideways, and tabs past the edge are easy to miss.
230
+
231
+ * **Never applies:** Hide the tab.
232
+ * **Temporarily unavailable:** Disable the tab, such as Deliveries before a webhook's first event, and state why in the open panel.
233
+
234
+ **Do:** Use a few short, parallel labels.
235
+
236
+ ```tsx
237
+ /** Do example for "Keep Tabs Few and Short" on the Tabs page: use a few short, parallel labels. @module */
238
+ import { Tabs } from '@tempoxyz/ds'
239
+
240
+ /** Renders the static preview, which the guideline card shows inert. */
241
+ export function Demo() {
242
+ return (
243
+ <Tabs.Root defaultValue="overview">
244
+ <Tabs.List aria-label="Webhook">
245
+ <Tabs.Tab value="overview">Overview</Tabs.Tab>
246
+ <Tabs.Tab value="deliveries">Deliveries</Tabs.Tab>
247
+ <Tabs.Tab value="settings">Settings</Tabs.Tab>
248
+ <Tabs.Indicator />
249
+ </Tabs.List>
250
+ </Tabs.Root>
251
+ )
252
+ }
253
+ ```
254
+
255
+ **Don't:** Add so many tabs that the row scrolls.
256
+
257
+ ```tsx
258
+ /**
259
+ * Don't example for "Keep Tabs Few and Short" on the Tabs page.
260
+ * Don't add so many tabs that the row scrolls.
261
+ * @module
262
+ */
263
+ import { style, Tabs } from '@tempoxyz/ds'
264
+
265
+ /** Renders the static preview, which the guideline card shows inert. */
266
+ export function Demo() {
267
+ return (
268
+ <Tabs.Root defaultValue="overview" {...styles.root()}>
269
+ <Tabs.List aria-label="Webhook">
270
+ <Tabs.Tab value="overview">Endpoint overview</Tabs.Tab>
271
+ <Tabs.Tab value="deliveries">Recent deliveries</Tabs.Tab>
272
+ <Tabs.Tab value="failed">Failed attempts</Tabs.Tab>
273
+ <Tabs.Tab value="secrets">Signing secrets</Tabs.Tab>
274
+ <Tabs.Tab value="settings">Settings</Tabs.Tab>
275
+ <Tabs.Indicator />
276
+ </Tabs.List>
277
+ </Tabs.Root>
278
+ )
279
+ }
280
+
281
+ namespace styles {
282
+ export const root = style({ maxWidth: '100% !custom' })
283
+ }
284
+ ```
285
+
286
+ ### Place One Indicator in Every Underline List
287
+
288
+ Put a `Tabs.Indicator` after the tabs in each underline `Tabs.List`. It slides a bar under the active tab.
289
+
290
+ **Do:** End every list with a `Tabs.Indicator`.
291
+
292
+ ```tsx
293
+ /** Do example for "Keep Tabs Few and Short" on the Tabs page: use a few short, parallel labels. @module */
294
+ import { Tabs } from '@tempoxyz/ds'
295
+
296
+ /** Renders the static preview, which the guideline card shows inert. */
297
+ export function Demo() {
298
+ return (
299
+ <Tabs.Root defaultValue="overview">
300
+ <Tabs.List aria-label="Webhook">
301
+ <Tabs.Tab value="overview">Overview</Tabs.Tab>
302
+ <Tabs.Tab value="deliveries">Deliveries</Tabs.Tab>
303
+ <Tabs.Tab value="settings">Settings</Tabs.Tab>
304
+ <Tabs.Indicator />
305
+ </Tabs.List>
306
+ </Tabs.Root>
307
+ )
308
+ }
309
+ ```
310
+
311
+ **Don't:** Leave out the indicator, so only the label marks the active tab.
312
+
313
+ ```tsx
314
+ /**
315
+ * Don't example for "Place One Indicator in Every List" on the Tabs page.
316
+ * Don't leave out the indicator, so only the label marks the active tab.
317
+ * @module
318
+ */
319
+ import { Tabs } from '@tempoxyz/ds'
320
+
321
+ /** Renders the static preview, which the guideline card shows inert. */
322
+ export function Demo() {
323
+ return (
324
+ <Tabs.Root defaultValue="overview">
325
+ <Tabs.List aria-label="Webhook">
326
+ <Tabs.Tab value="overview">Overview</Tabs.Tab>
327
+ <Tabs.Tab value="deliveries">Deliveries</Tabs.Tab>
328
+ <Tabs.Tab value="settings">Settings</Tabs.Tab>
329
+ </Tabs.List>
330
+ </Tabs.Root>
331
+ )
332
+ }
333
+ ```
334
+
335
+ ### Keep Panels Independent
336
+
337
+ Make each panel complete on its own. A Save button in one panel can't show errors in another, so use a [Stepper](/docs/components/stepper) flow or one longer form.
338
+
339
+ **Do:** Keep the fields of one form together.
340
+
341
+ ```tsx
342
+ /** Do example for "Keep Panels Independent" on the Tabs page: keep the fields of one form together. @module */
343
+ import { Button, Field, Stack, style, TextInput } from '@tempoxyz/ds'
344
+
345
+ /** Renders the static preview, which the guideline card shows inert. */
346
+ export function Demo() {
347
+ return (
348
+ <Stack gap="16" {...styles.fill()}>
349
+ <Field.Root>
350
+ <Field.Label>Key name</Field.Label>
351
+ <TextInput.Group>
352
+ <TextInput.Control defaultValue="Checkout server" />
353
+ </TextInput.Group>
354
+ </Field.Root>
355
+ <Field.Root>
356
+ <Field.Label>Daily limit</Field.Label>
357
+ <TextInput.Group>
358
+ <TextInput.Control defaultValue="5,000.00 USDC" />
359
+ </TextInput.Group>
360
+ </Field.Root>
361
+ <div {...styles.actions()}>
362
+ <Button size="small">Save key</Button>
363
+ </div>
364
+ </Stack>
365
+ )
366
+ }
367
+
368
+ namespace styles {
369
+ export const actions = style({ columnGap: '8', display: 'flex', justifyContent: 'flex-end' })
370
+
371
+ export const fill = style({ width: '100% !custom' })
372
+ }
373
+ ```
374
+
375
+ **Don't:** Split a form across tabs.
376
+
377
+ ```tsx
378
+ /** Don't example for "Keep Panels Independent" on the Tabs page. Don't split a form across tabs. @module */
379
+ import { Button, Field, Stack, style, Tabs, TextInput } from '@tempoxyz/ds'
380
+
381
+ /** Renders the static preview, which the guideline card shows inert. */
382
+ export function Demo() {
383
+ return (
384
+ <Tabs.Root defaultValue="details" {...styles.fill()}>
385
+ <Tabs.List aria-label="Key" size="small">
386
+ <Tabs.Tab value="details">Details</Tabs.Tab>
387
+ <Tabs.Tab value="limits">Limits</Tabs.Tab>
388
+ <Tabs.Indicator />
389
+ </Tabs.List>
390
+ <Tabs.Panel value="details">
391
+ <Stack gap="16" {...styles.panel()}>
392
+ <Field.Root>
393
+ <Field.Label>Key name</Field.Label>
394
+ <TextInput.Group>
395
+ <TextInput.Control defaultValue="Checkout server" />
396
+ </TextInput.Group>
397
+ </Field.Root>
398
+ <div {...styles.actions()}>
399
+ <Button size="small">Save key</Button>
400
+ </div>
401
+ </Stack>
402
+ </Tabs.Panel>
403
+ </Tabs.Root>
404
+ )
405
+ }
406
+
407
+ namespace styles {
408
+ export const actions = style({ columnGap: '8', display: 'flex', justifyContent: 'flex-end' })
409
+
410
+ export const fill = style({ width: '100% !custom' })
411
+
412
+ export const panel = style({ marginBlockStart: '16' })
413
+ }
414
+ ```
415
+
416
+ ### Keep the Selected Tab on Reload
417
+
418
+ If a tab marks a significant view, store it in the URL. Control `Tabs.Root` with `value` and `onValueChange`.
419
+
420
+ **Do:** Store the tab in the URL, such as `?tab=deliveries`, so a reload or a shared link opens it.
421
+
422
+ ```tsx
423
+ /**
424
+ * Do example for "Keep the Selected Tab on Reload" on the Tabs page.
425
+ * Store the tab in the URL, such as `?tab=deliveries`, so a reload or a shared link opens it.
426
+ * @module
427
+ */
428
+ import { style, Tabs } from '@tempoxyz/ds'
429
+
430
+ /** Renders the static preview, which the guideline card shows inert. */
431
+ export function Demo() {
432
+ return (
433
+ <div {...styles.page()}>
434
+ <span {...styles.address()}>console.tempo.xyz/webhooks/wh_8f3a?tab=deliveries</span>
435
+ <Tabs.Root defaultValue="deliveries">
436
+ <Tabs.List aria-label="Webhook" size="small">
437
+ <Tabs.Tab value="overview">Overview</Tabs.Tab>
438
+ <Tabs.Tab value="deliveries">Deliveries</Tabs.Tab>
439
+ <Tabs.Tab value="settings">Settings</Tabs.Tab>
440
+ <Tabs.Indicator />
441
+ </Tabs.List>
442
+ </Tabs.Root>
443
+ </div>
444
+ )
445
+ }
446
+
447
+ namespace styles {
448
+ export const address = style({
449
+ backgroundColor: 'container.regular',
450
+ borderRadius: 'full',
451
+ color: 'content.secondary',
452
+ cornerShape: 'round',
453
+ paddingBlock: '4',
454
+ paddingInline: '12',
455
+ typography: 'body.b3',
456
+ })
457
+
458
+ export const page = style({ display: 'flex', flexDirection: 'column', rowGap: '16' })
459
+ }
460
+ ```
461
+
462
+ **Don't:** Reset a reloaded or shared page to the first tab.
463
+
464
+ ```tsx
465
+ /**
466
+ * Don't example for "Keep the Selected Tab on Reload" on the Tabs page.
467
+ * Don't reset a reloaded or shared page to the first tab.
468
+ * @module
469
+ */
470
+ import { style, Tabs } from '@tempoxyz/ds'
471
+
472
+ /** Renders the static preview, which the guideline card shows inert. */
473
+ export function Demo() {
474
+ return (
475
+ <div {...styles.page()}>
476
+ <span {...styles.address()}>console.tempo.xyz/webhooks/wh_8f3a</span>
477
+ <Tabs.Root defaultValue="overview">
478
+ <Tabs.List aria-label="Webhook" size="small">
479
+ <Tabs.Tab value="overview">Overview</Tabs.Tab>
480
+ <Tabs.Tab value="deliveries">Deliveries</Tabs.Tab>
481
+ <Tabs.Tab value="settings">Settings</Tabs.Tab>
482
+ <Tabs.Indicator />
483
+ </Tabs.List>
484
+ </Tabs.Root>
485
+ </div>
486
+ )
487
+ }
488
+
489
+ namespace styles {
490
+ export const address = style({
491
+ backgroundColor: 'container.regular',
492
+ borderRadius: 'full',
493
+ color: 'content.secondary',
494
+ cornerShape: 'round',
495
+ paddingBlock: '4',
496
+ paddingInline: '12',
497
+ typography: 'body.b3',
498
+ })
499
+
500
+ export const page = style({ display: 'flex', flexDirection: 'column', rowGap: '16' })
501
+ }
502
+ ```
503
+
504
+ ### Expand Tabs in Narrow Containers
505
+
506
+ Set `expand` in a narrow container, such as a [Surface](/docs/components/surface) or a phone-width column. Leave it off across a wide page, where stretched tabs drift apart.
507
+
508
+ **Do:** Stretch the tabs across a narrow card with `expand`.
509
+
510
+ ```tsx
511
+ /**
512
+ * Do example for "Expand Tabs in Narrow Containers" on the Tabs page.
513
+ * Stretch the tabs across a narrow card with `expand`.
514
+ * @module
515
+ */
516
+ import { style, Surface, Tabs } from '@tempoxyz/ds'
517
+
518
+ /** Renders the static preview, which the guideline card shows inert. */
519
+ export function Demo() {
520
+ return (
521
+ <Surface size="small" {...styles.card()}>
522
+ <Tabs.Root defaultValue="balances">
523
+ <Tabs.List aria-label="Wallet" expand size="small">
524
+ <Tabs.Tab value="balances">Balances</Tabs.Tab>
525
+ <Tabs.Tab value="activity">Activity</Tabs.Tab>
526
+ <Tabs.Indicator />
527
+ </Tabs.List>
528
+ </Tabs.Root>
529
+ </Surface>
530
+ )
531
+ }
532
+
533
+ namespace styles {
534
+ export const card = style({ width: '16rem !custom' })
535
+ }
536
+ ```
537
+
538
+ **Don't:** Leave a gap at the end of the row in a narrow card.
539
+
540
+ ```tsx
541
+ /**
542
+ * Don't example for "Expand Tabs in Narrow Containers" on the Tabs page.
543
+ * Don't leave a gap at the end of the row in a narrow card.
544
+ * @module
545
+ */
546
+ import { style, Surface, Tabs } from '@tempoxyz/ds'
547
+
548
+ /** Renders the static preview, which the guideline card shows inert. */
549
+ export function Demo() {
550
+ return (
551
+ <Surface size="small" {...styles.card()}>
552
+ <Tabs.Root defaultValue="balances">
553
+ <Tabs.List aria-label="Wallet" size="small">
554
+ <Tabs.Tab value="balances">Balances</Tabs.Tab>
555
+ <Tabs.Tab value="activity">Activity</Tabs.Tab>
556
+ <Tabs.Indicator />
557
+ </Tabs.List>
558
+ </Tabs.Root>
559
+ </Surface>
560
+ )
561
+ }
562
+
563
+ namespace styles {
564
+ export const card = style({ width: '16rem !custom' })
565
+ }
566
+ ```
567
+
568
+ ## Content
569
+
570
+ * Use nouns that name the panel's content, such as Overview, Activity, or Settings.
571
+ * Keep labels parallel in form and length, such as Send, Receive, and Swap.
572
+ * Add an icon only if every tab in the list has one.
573
+ * Don't repeat the page title in each label, such as Webhook overview and Webhook settings.
574
+
575
+ ## Accessibility
576
+
577
+ Tabs follow the [WAI-ARIA tabs pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/), with manual activation by default.
578
+
579
+ ### Semantics
580
+
581
+ * **Tabs.List (tablist):** Holds the tabs, and needs its own name.
582
+ * **Tabs.Tab (tab):** A button. The active tab is selected and points at its panel.
583
+ * **Tabs.Panel (tabpanel):** Named by its tab. Hidden panels unmount unless you set `keepMounted`, which find in page requires.
584
+ * **Disabled Tabs (aria-disabled):** Reachable with the arrow keys, but can't be activated or shown first.
585
+ * **Tabs.Indicator:** Decorative, and ignores pointer events. Under reduced motion, it moves without sliding.
586
+
587
+ ### Keyboard
588
+
589
+ * **Move into the List (Tab):** Moves focus to the active tab, then to the open panel.
590
+ * **Move to the Next Tab (Right Arrow):** Moves focus to the next tab, and wraps at the end.
591
+ * **Move to the Previous Tab (Left Arrow):** Moves focus to the previous tab, and wraps at the start.
592
+ * **Move to the First Tab (Home):** Moves focus to the first tab.
593
+ * **Move to the Last Tab (End):** Moves focus to the last tab.
594
+ * **Activate the Tab (Enter or Space):** Activates the focused tab and shows its panel.
595
+
596
+ Set `activateOnFocus` on `Tabs.List` to activate a tab on focus. Use it only if panels render without delay.
597
+
598
+ ### Focus
599
+
600
+ * **One Tab Stop:** Only the active tab is in the Tab order. Arrow keys move between tabs.
601
+ * **Focusable Panel:** The open panel is focusable, so Tab moves into it even if it holds no controls.
602
+
603
+ ### Your Responsibilities
604
+
605
+ * **Name the List (SC 4.1.2):** Name the tab list, such as "Sections".
606
+
607
+ ## Related
608
+
609
+ [ChoiceGroup](/docs/components/choice-group)
610
+
611
+ Use for one value that changes a view.
612
+
613
+ [SidebarMenu](/docs/components/sidebar-menu)
614
+
615
+ Use for navigating between pages.
616
+
617
+ [Accordion](/docs/components/accordion)
618
+
619
+ Use for sections you open together.
620
+
621
+ [Snippet](/docs/components/snippet)
622
+
623
+ Use for a command with a tab per tool.
624
+
625
+ [Navigation](/docs/patterns/navigation)
626
+
627
+ Covers choosing between navigation components.