@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.
- package/dist/docs/AGENTS.md +9 -0
- package/dist/docs/components/accordion.md +489 -0
- package/dist/docs/components/address-card.md +147 -0
- package/dist/docs/components/agent-logo.md +194 -0
- package/dist/docs/components/alert-dialog.md +631 -0
- package/dist/docs/components/alert.md +448 -0
- package/dist/docs/components/amount-input.md +305 -0
- package/dist/docs/components/amount.md +794 -0
- package/dist/docs/components/app-shell.md +559 -0
- package/dist/docs/components/asset-chip.md +294 -0
- package/dist/docs/components/autocomplete.md +619 -0
- package/dist/docs/components/avatar.md +321 -0
- package/dist/docs/components/badge.md +339 -0
- package/dist/docs/components/badged-logo.md +116 -0
- package/dist/docs/components/banner.md +379 -0
- package/dist/docs/components/bar-chart.md +208 -0
- package/dist/docs/components/breadcrumbs.md +380 -0
- package/dist/docs/components/button-group.md +286 -0
- package/dist/docs/components/button.md +650 -0
- package/dist/docs/components/calendar.md +375 -0
- package/dist/docs/components/callout.md +96 -0
- package/dist/docs/components/checkbox-group.md +521 -0
- package/dist/docs/components/checkbox.md +467 -0
- package/dist/docs/components/choice-group.md +516 -0
- package/dist/docs/components/choicebox.md +641 -0
- package/dist/docs/components/code.md +100 -0
- package/dist/docs/components/combobox.md +939 -0
- package/dist/docs/components/container.md +257 -0
- package/dist/docs/components/copy-button.md +642 -0
- package/dist/docs/components/date-picker.md +514 -0
- package/dist/docs/components/dialog.md +1332 -0
- package/dist/docs/components/drawer.md +966 -0
- package/dist/docs/components/empty.md +340 -0
- package/dist/docs/components/field.md +570 -0
- package/dist/docs/components/fieldset.md +398 -0
- package/dist/docs/components/frame.md +434 -0
- package/dist/docs/components/gauge.md +299 -0
- package/dist/docs/components/get-started-visual.md +117 -0
- package/dist/docs/components/grid.md +288 -0
- package/dist/docs/components/hero-visual.md +155 -0
- package/dist/docs/components/hex.md +487 -0
- package/dist/docs/components/icon-tile.md +292 -0
- package/dist/docs/components/identicon.md +371 -0
- package/dist/docs/components/inline.md +233 -0
- package/dist/docs/components/inset.md +225 -0
- package/dist/docs/components/kbd.md +423 -0
- package/dist/docs/components/list-group.md +981 -0
- package/dist/docs/components/loading-dots.md +237 -0
- package/dist/docs/components/menu.md +934 -0
- package/dist/docs/components/native-select.md +204 -0
- package/dist/docs/components/network-logo.md +248 -0
- package/dist/docs/components/number-field.md +543 -0
- package/dist/docs/components/otp-field.md +616 -0
- package/dist/docs/components/pagination.md +516 -0
- package/dist/docs/components/popover.md +544 -0
- package/dist/docs/components/progress.md +388 -0
- package/dist/docs/components/qr.md +314 -0
- package/dist/docs/components/radio-group.md +528 -0
- package/dist/docs/components/secret-value.md +406 -0
- package/dist/docs/components/select.md +751 -0
- package/dist/docs/components/separator.md +379 -0
- package/dist/docs/components/sidebar-menu.md +922 -0
- package/dist/docs/components/skeleton.md +517 -0
- package/dist/docs/components/slider.md +539 -0
- package/dist/docs/components/snippet.md +424 -0
- package/dist/docs/components/spinner.md +216 -0
- package/dist/docs/components/split-bar.md +139 -0
- package/dist/docs/components/split-button.md +464 -0
- package/dist/docs/components/stack.md +299 -0
- package/dist/docs/components/status-chip.md +226 -0
- package/dist/docs/components/status-indicator.md +119 -0
- package/dist/docs/components/status-row.md +174 -0
- package/dist/docs/components/stepper.md +451 -0
- package/dist/docs/components/success-hero.md +157 -0
- package/dist/docs/components/surface.md +639 -0
- package/dist/docs/components/switch.md +472 -0
- package/dist/docs/components/table.md +967 -0
- package/dist/docs/components/tabs.md +627 -0
- package/dist/docs/components/tempo-logo.md +185 -0
- package/dist/docs/components/text-input.md +624 -0
- package/dist/docs/components/textarea.md +352 -0
- package/dist/docs/components/toast.md +535 -0
- package/dist/docs/components/token-logo.md +371 -0
- package/dist/docs/components/token.md +247 -0
- package/dist/docs/components/tooltip.md +490 -0
- package/dist/docs/components/verification-code.md +116 -0
- package/dist/docs/components/visual.md +249 -0
- package/dist/docs/components.md +203 -0
- package/dist/docs/foundations/accessibility.md +377 -0
- package/dist/docs/foundations/agents.md +150 -0
- package/dist/docs/foundations/color.md +522 -0
- package/dist/docs/foundations/content/tone.md +194 -0
- package/dist/docs/foundations/content/voice.md +194 -0
- package/dist/docs/foundations/content/writing-style.md +406 -0
- package/dist/docs/foundations/iconography.md +282 -0
- package/dist/docs/foundations/intent.md +360 -0
- package/dist/docs/foundations/layout.md +508 -0
- package/dist/docs/foundations/linter.md +296 -0
- package/dist/docs/foundations/motion.md +151 -0
- package/dist/docs/foundations/radius-and-padding.md +86 -0
- package/dist/docs/foundations/typography.md +266 -0
- package/dist/docs/index.md +137 -0
- package/dist/docs/introduction/faq.md +132 -0
- package/dist/docs/introduction/getting-started.md +377 -0
- package/dist/docs/patterns/blockchain-values.md +709 -0
- package/dist/docs/patterns/dashboards.md +638 -0
- package/dist/docs/patterns/destructive-actions.md +626 -0
- package/dist/docs/patterns/empty-states.md +612 -0
- package/dist/docs/patterns/errors-and-validation.md +808 -0
- package/dist/docs/patterns/feedback-and-status.md +518 -0
- package/dist/docs/patterns/forms.md +679 -0
- package/dist/docs/patterns/loading.md +630 -0
- package/dist/docs/patterns/navigation.md +397 -0
- package/dist/docs/patterns/payments.md +765 -0
- package/dist/docs/patterns/responsive-layout.md +997 -0
- package/dist/docs/patterns/tables-and-lists.md +964 -0
- package/dist/docs/products/tempo-console.md +671 -0
- package/dist/docs/products/tempo-performance.md +437 -0
- package/dist/docs/products/tempo-wallet.md +438 -0
- package/package.json +1 -1
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
# TextInput
|
|
2
|
+
|
|
3
|
+
A text field with optional prefix, suffix, and clear button.
|
|
4
|
+
|
|
5
|
+
[View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/TextInput.tsx)
|
|
6
|
+
|
|
7
|
+
Figma: [Inputs/Input](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=5227-3846) (`TextInput.Group`), [Inputs/Search Input](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=5227-2265) (`TextInput.Group`), [Inputs/Text Input](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=5227-1285) (`TextInput.Group`), [Search](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=1186-3365) (`TextInput.Group`), [Text Input](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=1186-3316) (`TextInput.Group`)
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
An input is a filled text field composed from a group, an optional prefix and suffix, a control, and a clear button.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### Basic
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Field, style, TextInput } from '@tempoxyz/ds'
|
|
19
|
+
|
|
20
|
+
export const fill = true
|
|
21
|
+
export function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Field.Root {...styles.field()}>
|
|
24
|
+
<Field.Label>To</Field.Label>
|
|
25
|
+
<TextInput.Group>
|
|
26
|
+
<TextInput.Control autoComplete="email" placeholder="Address, email or contact" />
|
|
27
|
+
</TextInput.Group>
|
|
28
|
+
<Field.Description>Paste an address or pick a contact</Field.Description>
|
|
29
|
+
</Field.Root>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
namespace styles {
|
|
34
|
+
export const field = style({ maxWidth: '24rem !custom' })
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/TextInput/Basic.tsx)
|
|
39
|
+
|
|
40
|
+
### Icons
|
|
41
|
+
|
|
42
|
+
Put an icon that gives the field its meaning, such as `Search` or `Mail`, in `TextInput.Prefix`. Put an icon for an action on the field, such as paste, in `TextInput.Suffix`.
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { Field, style, TextInput } from '@tempoxyz/ds'
|
|
46
|
+
import { Clipboard, Search } from '@tempoxyz/ds/icons'
|
|
47
|
+
|
|
48
|
+
export const fill = true
|
|
49
|
+
export function Demo() {
|
|
50
|
+
return (
|
|
51
|
+
<Field.Root {...styles.field()}>
|
|
52
|
+
<Field.Label>Recipient</Field.Label>
|
|
53
|
+
<TextInput.Group>
|
|
54
|
+
<TextInput.Prefix>
|
|
55
|
+
<Search />
|
|
56
|
+
</TextInput.Prefix>
|
|
57
|
+
<TextInput.Control defaultValue="maya@studio.co" />
|
|
58
|
+
<TextInput.Suffix>
|
|
59
|
+
<Clipboard />
|
|
60
|
+
</TextInput.Suffix>
|
|
61
|
+
</TextInput.Group>
|
|
62
|
+
<Field.Description>Paste an address or pick a contact</Field.Description>
|
|
63
|
+
</Field.Root>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
namespace styles {
|
|
68
|
+
export const field = style({ maxWidth: '24rem !custom' })
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/TextInput/Icons.tsx)
|
|
73
|
+
|
|
74
|
+
### Search
|
|
75
|
+
|
|
76
|
+
Add a `Search` icon in `TextInput.Prefix` and a `TextInput.Clear`. The clear button shows once the field has a value, and Escape empties the field before it closes an enclosing [Dialog](/docs/components/dialog).
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
import { Field, style, TextInput } from '@tempoxyz/ds'
|
|
80
|
+
import { Search } from '@tempoxyz/ds/icons'
|
|
81
|
+
|
|
82
|
+
export const fill = true
|
|
83
|
+
export function Demo() {
|
|
84
|
+
return (
|
|
85
|
+
<Field.Root {...styles.field()}>
|
|
86
|
+
<TextInput.Group>
|
|
87
|
+
<TextInput.Prefix>
|
|
88
|
+
<Search />
|
|
89
|
+
</TextInput.Prefix>
|
|
90
|
+
<TextInput.Control
|
|
91
|
+
aria-label="Search contacts"
|
|
92
|
+
defaultValue="Maya"
|
|
93
|
+
placeholder="Name, email or address"
|
|
94
|
+
type="search"
|
|
95
|
+
/>
|
|
96
|
+
<TextInput.Clear />
|
|
97
|
+
</TextInput.Group>
|
|
98
|
+
</Field.Root>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
namespace styles {
|
|
103
|
+
export const field = style({ maxWidth: '24rem !custom' })
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/TextInput/Search.tsx)
|
|
108
|
+
|
|
109
|
+
### Variant
|
|
110
|
+
|
|
111
|
+
Set `variant` on `TextInput.Group` to `default` (default) or `outlined`, which draws a 1px line instead of the fill.
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
import { Field, style, TextInput } from '@tempoxyz/ds'
|
|
115
|
+
|
|
116
|
+
export function Demo() {
|
|
117
|
+
return (
|
|
118
|
+
<div {...styles.grid()}>
|
|
119
|
+
{(['default', 'outlined'] as const).map((variant) => (
|
|
120
|
+
<Field.Root key={variant}>
|
|
121
|
+
<Field.Label>To</Field.Label>
|
|
122
|
+
<TextInput.Group variant={variant}>
|
|
123
|
+
<TextInput.Control placeholder="Address, email or contact" />
|
|
124
|
+
</TextInput.Group>
|
|
125
|
+
<Field.Description>Paste an address or pick a contact</Field.Description>
|
|
126
|
+
</Field.Root>
|
|
127
|
+
))}
|
|
128
|
+
</div>
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
namespace styles {
|
|
133
|
+
export const grid = style({
|
|
134
|
+
alignItems: 'start',
|
|
135
|
+
display: 'grid',
|
|
136
|
+
gap: '24',
|
|
137
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(min(280px, 100%), 1fr)) !custom',
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/TextInput/Variant.tsx)
|
|
143
|
+
|
|
144
|
+
### Size
|
|
145
|
+
|
|
146
|
+
Set `size` on `TextInput.Group` to `medium` (default) or `large`, a 52px search bar with 20px icons and larger corners.
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
import { Field, style, TextInput } from '@tempoxyz/ds'
|
|
150
|
+
import { Search } from '@tempoxyz/ds/icons'
|
|
151
|
+
|
|
152
|
+
export function Demo() {
|
|
153
|
+
return (
|
|
154
|
+
<div {...styles.grid()}>
|
|
155
|
+
{(['medium', 'large'] as const).map((size) => (
|
|
156
|
+
<Field.Root key={size}>
|
|
157
|
+
<TextInput.Group size={size}>
|
|
158
|
+
<TextInput.Prefix>
|
|
159
|
+
<Search />
|
|
160
|
+
</TextInput.Prefix>
|
|
161
|
+
<TextInput.Control
|
|
162
|
+
aria-label="Search tokens"
|
|
163
|
+
placeholder="Search tokens"
|
|
164
|
+
type="search"
|
|
165
|
+
/>
|
|
166
|
+
<TextInput.Clear />
|
|
167
|
+
</TextInput.Group>
|
|
168
|
+
</Field.Root>
|
|
169
|
+
))}
|
|
170
|
+
</div>
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
namespace styles {
|
|
175
|
+
export const grid = style({
|
|
176
|
+
alignItems: 'start',
|
|
177
|
+
display: 'grid',
|
|
178
|
+
gap: '24',
|
|
179
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(min(280px, 100%), 1fr)) !custom',
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/TextInput/Size.tsx)
|
|
185
|
+
|
|
186
|
+
### Appearance
|
|
187
|
+
|
|
188
|
+
Set `appearance` on `TextInput.Group` to `base` (default) or `overlay`, which draws a translucent fill and white text over an image or video.
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
import { Field, style, TextInput } from '@tempoxyz/ds'
|
|
192
|
+
import { Search } from '@tempoxyz/ds/icons'
|
|
193
|
+
|
|
194
|
+
export const fill = true
|
|
195
|
+
export function Demo() {
|
|
196
|
+
return (
|
|
197
|
+
<div {...styles.backdrop()}>
|
|
198
|
+
<Field.Root {...styles.field()}>
|
|
199
|
+
<TextInput.Group appearance="overlay" size="large">
|
|
200
|
+
<TextInput.Prefix>
|
|
201
|
+
<Search />
|
|
202
|
+
</TextInput.Prefix>
|
|
203
|
+
<TextInput.Control aria-label="Search places" placeholder="Search places" type="search" />
|
|
204
|
+
<TextInput.Clear />
|
|
205
|
+
</TextInput.Group>
|
|
206
|
+
</Field.Root>
|
|
207
|
+
</div>
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
namespace styles {
|
|
212
|
+
// A dark gradient stands in for the image or video under an overlay field.
|
|
213
|
+
export const backdrop = style({
|
|
214
|
+
backgroundImage: 'linear-gradient(135deg, #3d3d3d, #141414) !custom',
|
|
215
|
+
borderRadius: 'sm',
|
|
216
|
+
padding: '32',
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
export const field = style({ maxWidth: '24rem !custom' })
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/TextInput/Appearance.tsx)
|
|
224
|
+
|
|
225
|
+
### Invalid
|
|
226
|
+
|
|
227
|
+
Set `invalid` or `success` on `TextInput.Group`, or inherit either from `Field.Root`. A state set after mount plays a one-shot nudge or pop.
|
|
228
|
+
|
|
229
|
+
```tsx
|
|
230
|
+
import { Field, style, TextInput } from '@tempoxyz/ds'
|
|
231
|
+
import { useState } from 'react'
|
|
232
|
+
|
|
233
|
+
export function Demo() {
|
|
234
|
+
return (
|
|
235
|
+
<div {...styles.grid()}>
|
|
236
|
+
<Send />
|
|
237
|
+
<Field.Root
|
|
238
|
+
validate={(value) => (String(value).includes('@') ? null : 'Enter a valid email.')}
|
|
239
|
+
validationMode="onChange"
|
|
240
|
+
>
|
|
241
|
+
<Field.Label>Email</Field.Label>
|
|
242
|
+
<TextInput.Group>
|
|
243
|
+
<TextInput.Control defaultValue="alice@example.com" type="email" />
|
|
244
|
+
</TextInput.Group>
|
|
245
|
+
<Field.Description>Remove the @ to swap in the error.</Field.Description>
|
|
246
|
+
<Field.Error />
|
|
247
|
+
</Field.Root>
|
|
248
|
+
<Field.Root invalid>
|
|
249
|
+
<Field.Label>Email</Field.Label>
|
|
250
|
+
<TextInput.Group>
|
|
251
|
+
<TextInput.Control defaultValue="alice" type="email" />
|
|
252
|
+
</TextInput.Group>
|
|
253
|
+
<Field.Description>Used for receipts.</Field.Description>
|
|
254
|
+
<Field.Error match>Enter a valid email.</Field.Error>
|
|
255
|
+
</Field.Root>
|
|
256
|
+
</div>
|
|
257
|
+
)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function Send() {
|
|
261
|
+
const [amount, setAmount] = useState('')
|
|
262
|
+
const invalid = Number(amount) > 1240.5
|
|
263
|
+
|
|
264
|
+
return (
|
|
265
|
+
<Field.Root invalid={invalid} success={amount !== '' && !invalid}>
|
|
266
|
+
<Field.Label>You send</Field.Label>
|
|
267
|
+
<TextInput.Group>
|
|
268
|
+
<TextInput.Prefix>$</TextInput.Prefix>
|
|
269
|
+
<TextInput.Control inputMode="decimal" onValueChange={setAmount} placeholder="0.00" />
|
|
270
|
+
<TextInput.Suffix>USDC</TextInput.Suffix>
|
|
271
|
+
</TextInput.Group>
|
|
272
|
+
<Field.Description>Balance 1,240.50 USDC</Field.Description>
|
|
273
|
+
<Field.Error match={invalid}>Exceeds your balance.</Field.Error>
|
|
274
|
+
</Field.Root>
|
|
275
|
+
)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
namespace styles {
|
|
279
|
+
export const grid = style({
|
|
280
|
+
alignItems: 'start',
|
|
281
|
+
display: 'grid',
|
|
282
|
+
gap: '24',
|
|
283
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(min(280px, 100%), 1fr)) !custom',
|
|
284
|
+
})
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/TextInput/Invalid.tsx)
|
|
289
|
+
|
|
290
|
+
### Disabled
|
|
291
|
+
|
|
292
|
+
Disable a field only when the app sets the value, and say why in the `Field.Description`.
|
|
293
|
+
|
|
294
|
+
```tsx
|
|
295
|
+
import { Field, style, TextInput } from '@tempoxyz/ds'
|
|
296
|
+
|
|
297
|
+
export const fill = true
|
|
298
|
+
export function Demo() {
|
|
299
|
+
return (
|
|
300
|
+
<Field.Root disabled {...styles.field()}>
|
|
301
|
+
<Field.Label>Network</Field.Label>
|
|
302
|
+
<TextInput.Group>
|
|
303
|
+
<TextInput.Control defaultValue="Tempo" />
|
|
304
|
+
</TextInput.Group>
|
|
305
|
+
<Field.Description>Set by the app you are paying</Field.Description>
|
|
306
|
+
</Field.Root>
|
|
307
|
+
)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
namespace styles {
|
|
311
|
+
export const field = style({ maxWidth: '24rem !custom' })
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/TextInput/Disabled.tsx)
|
|
316
|
+
|
|
317
|
+
## Anatomy
|
|
318
|
+
|
|
319
|
+
Import the component and assemble its parts.
|
|
320
|
+
|
|
321
|
+
```tsx
|
|
322
|
+
import { TextInput } from '@tempoxyz/ds'
|
|
323
|
+
|
|
324
|
+
<TextInput.Group>
|
|
325
|
+
<TextInput.Prefix />
|
|
326
|
+
<TextInput.Control />
|
|
327
|
+
<TextInput.Suffix />
|
|
328
|
+
<TextInput.Clear />
|
|
329
|
+
</TextInput.Group>
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## Guidelines
|
|
333
|
+
|
|
334
|
+
### When to Use
|
|
335
|
+
|
|
336
|
+
* Collect one line of text, such as an email or a 0x address.
|
|
337
|
+
* Search a list or table, with a `Search` icon in `TextInput.Prefix` and a `TextInput.Clear`.
|
|
338
|
+
|
|
339
|
+
### When Not to Use
|
|
340
|
+
|
|
341
|
+
* Use [AmountInput](/docs/components/amount-input) for token and fiat amounts. It rejects non-decimals and adds a Max action.
|
|
342
|
+
* Use [NumberField](/docs/components/number-field) for quantities that step up and down.
|
|
343
|
+
* Use [Textarea](/docs/components/textarea) for text over one line.
|
|
344
|
+
* Use [OtpField](/docs/components/otp-field) for one-time passcodes.
|
|
345
|
+
* Use [Select](/docs/components/select) or [Combobox](/docs/components/combobox) if the value must come from a list, and [Autocomplete](/docs/components/autocomplete) if a list only suggests values.
|
|
346
|
+
|
|
347
|
+
### Always Show a Label
|
|
348
|
+
|
|
349
|
+
A placeholder disappears on the first keystroke. Use it only for a format example, such as `0x…`. Leave out the visible label only when the dialog title already names the field, such as a search field, and set `aria-label`.
|
|
350
|
+
|
|
351
|
+
**Do:** Name the field in a `Field.Label` and keep the placeholder as a format hint.
|
|
352
|
+
|
|
353
|
+
```tsx
|
|
354
|
+
/**
|
|
355
|
+
* Do example for "Always Show a Label" on the TextInput page.
|
|
356
|
+
* Name the field in a `Field.Label` and keep the placeholder as a format hint.
|
|
357
|
+
* @module
|
|
358
|
+
*/
|
|
359
|
+
import { Field, style, TextInput } from '@tempoxyz/ds'
|
|
360
|
+
|
|
361
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
362
|
+
export function Demo() {
|
|
363
|
+
return (
|
|
364
|
+
<Field.Root {...styles.field()}>
|
|
365
|
+
<Field.Label>Recipient address</Field.Label>
|
|
366
|
+
<TextInput.Group>
|
|
367
|
+
<TextInput.Control placeholder="0x…" />
|
|
368
|
+
</TextInput.Group>
|
|
369
|
+
</Field.Root>
|
|
370
|
+
)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
namespace styles {
|
|
374
|
+
export const field = style({ maxWidth: '18rem !custom', width: '100% !custom' })
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
**Don't:** Use the placeholder as the only label.
|
|
379
|
+
|
|
380
|
+
```tsx
|
|
381
|
+
/**
|
|
382
|
+
* Don't example for "Always Show a Label" on the TextInput page.
|
|
383
|
+
* Don't use the placeholder as the only label.
|
|
384
|
+
* @module
|
|
385
|
+
*/
|
|
386
|
+
import { style, TextInput } from '@tempoxyz/ds'
|
|
387
|
+
|
|
388
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
389
|
+
export function Demo() {
|
|
390
|
+
return (
|
|
391
|
+
<TextInput.Group {...styles.field()}>
|
|
392
|
+
<TextInput.Control aria-label="Recipient address" placeholder="Recipient address" />
|
|
393
|
+
</TextInput.Group>
|
|
394
|
+
)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
namespace styles {
|
|
398
|
+
export const field = style({ maxWidth: '18rem !custom', width: '100% !custom' })
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Size the Field to Its Value
|
|
403
|
+
|
|
404
|
+
`TextInput.Group` fills its container. If the value is short, narrow it with `style` or `className`.
|
|
405
|
+
|
|
406
|
+
**Do:** Give a short value a short field, and a long value the full column.
|
|
407
|
+
|
|
408
|
+
```tsx
|
|
409
|
+
/**
|
|
410
|
+
* Do example for "Size the Field to Its Value" on the TextInput page.
|
|
411
|
+
* Give a short value a short field, and a long value the full column.
|
|
412
|
+
* @module
|
|
413
|
+
*/
|
|
414
|
+
import { Field, style, TextInput } from '@tempoxyz/ds'
|
|
415
|
+
|
|
416
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
417
|
+
export function Demo() {
|
|
418
|
+
return (
|
|
419
|
+
<div {...styles.form()}>
|
|
420
|
+
<Field.Root>
|
|
421
|
+
<Field.Label>TokenLogo symbol</Field.Label>
|
|
422
|
+
<TextInput.Group {...styles.short()}>
|
|
423
|
+
<TextInput.Control defaultValue="USDC" />
|
|
424
|
+
</TextInput.Group>
|
|
425
|
+
</Field.Root>
|
|
426
|
+
<Field.Root>
|
|
427
|
+
<Field.Label>Webhook URL</Field.Label>
|
|
428
|
+
<TextInput.Group>
|
|
429
|
+
<TextInput.Control defaultValue="https://api.example.com/hooks" type="url" />
|
|
430
|
+
</TextInput.Group>
|
|
431
|
+
</Field.Root>
|
|
432
|
+
</div>
|
|
433
|
+
)
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
namespace styles {
|
|
437
|
+
export const form = style({
|
|
438
|
+
display: 'grid',
|
|
439
|
+
gap: '16',
|
|
440
|
+
maxWidth: '18rem !custom',
|
|
441
|
+
width: '100% !custom',
|
|
442
|
+
})
|
|
443
|
+
|
|
444
|
+
export const short = style({ width: '7rem !custom' })
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
**Don't:** Stretch a four-character symbol across the column or squeeze a URL into a small box.
|
|
449
|
+
|
|
450
|
+
```tsx
|
|
451
|
+
/**
|
|
452
|
+
* Don't example for "Size the Field to Its Value" on the TextInput page.
|
|
453
|
+
* Don't stretch a four-character symbol across the column or squeeze a URL into a small box.
|
|
454
|
+
* @module
|
|
455
|
+
*/
|
|
456
|
+
import { Field, style, TextInput } from '@tempoxyz/ds'
|
|
457
|
+
|
|
458
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
459
|
+
export function Demo() {
|
|
460
|
+
return (
|
|
461
|
+
<div {...styles.form()}>
|
|
462
|
+
<Field.Root>
|
|
463
|
+
<Field.Label>TokenLogo symbol</Field.Label>
|
|
464
|
+
<TextInput.Group>
|
|
465
|
+
<TextInput.Control defaultValue="USDC" />
|
|
466
|
+
</TextInput.Group>
|
|
467
|
+
</Field.Root>
|
|
468
|
+
<Field.Root>
|
|
469
|
+
<Field.Label>Webhook URL</Field.Label>
|
|
470
|
+
<TextInput.Group {...styles.short()}>
|
|
471
|
+
<TextInput.Control defaultValue="https://api.example.com/hooks" type="url" />
|
|
472
|
+
</TextInput.Group>
|
|
473
|
+
</Field.Root>
|
|
474
|
+
</div>
|
|
475
|
+
)
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
namespace styles {
|
|
479
|
+
export const form = style({
|
|
480
|
+
display: 'grid',
|
|
481
|
+
gap: '16',
|
|
482
|
+
maxWidth: '18rem !custom',
|
|
483
|
+
width: '100% !custom',
|
|
484
|
+
})
|
|
485
|
+
|
|
486
|
+
export const short = style({ width: '7rem !custom' })
|
|
487
|
+
}
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### Use Prefixes and Suffixes for Fixed Context
|
|
491
|
+
|
|
492
|
+
Put a currency symbol, protocol, or search icon in `TextInput.Prefix`, and a unit such as `USDC` in `TextInput.Suffix`.
|
|
493
|
+
|
|
494
|
+
**Do:** Show the unit in `TextInput.Suffix` so people type only the number.
|
|
495
|
+
|
|
496
|
+
```tsx
|
|
497
|
+
/**
|
|
498
|
+
* Do example for "Use Prefixes and Suffixes for Fixed Context" on the TextInput page.
|
|
499
|
+
* Show the unit in `TextInput.Suffix` so people type only the number.
|
|
500
|
+
* @module
|
|
501
|
+
*/
|
|
502
|
+
import { Field, style, TextInput } from '@tempoxyz/ds'
|
|
503
|
+
|
|
504
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
505
|
+
export function Demo() {
|
|
506
|
+
return (
|
|
507
|
+
<Field.Root {...styles.field()}>
|
|
508
|
+
<Field.Label>Slippage tolerance</Field.Label>
|
|
509
|
+
<TextInput.Group>
|
|
510
|
+
<TextInput.Control defaultValue="0.5" inputMode="decimal" />
|
|
511
|
+
<TextInput.Suffix>%</TextInput.Suffix>
|
|
512
|
+
</TextInput.Group>
|
|
513
|
+
</Field.Root>
|
|
514
|
+
)
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
namespace styles {
|
|
518
|
+
export const field = style({ width: '9rem !custom' })
|
|
519
|
+
}
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
**Don't:** Make people type the unit into the value.
|
|
523
|
+
|
|
524
|
+
```tsx
|
|
525
|
+
/**
|
|
526
|
+
* Don't example for "Use Prefixes and Suffixes for Fixed Context" on the TextInput page.
|
|
527
|
+
* Don't make people type the unit into the value.
|
|
528
|
+
* @module
|
|
529
|
+
*/
|
|
530
|
+
import { Field, style, TextInput } from '@tempoxyz/ds'
|
|
531
|
+
|
|
532
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
533
|
+
export function Demo() {
|
|
534
|
+
return (
|
|
535
|
+
<Field.Root {...styles.field()}>
|
|
536
|
+
<Field.Label>Slippage tolerance</Field.Label>
|
|
537
|
+
<TextInput.Group>
|
|
538
|
+
<TextInput.Control defaultValue="0.5%" />
|
|
539
|
+
</TextInput.Group>
|
|
540
|
+
</Field.Root>
|
|
541
|
+
)
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
namespace styles {
|
|
545
|
+
export const field = style({ width: '9rem !custom' })
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
* **Content:** Keep prefixes and suffixes to a symbol, icon, or one short word. Put other buttons beside the group, not in a suffix.
|
|
550
|
+
* **Icons:** Use a leading icon for meaning, such as `Search`, and a trailing icon for an action on the field, such as paste or scan.
|
|
551
|
+
* **Clear:** `TextInput.Clear` appears only inside a `Field.Root` once the control has a value. Add it to search fields and filters, not to one-time forms.
|
|
552
|
+
|
|
553
|
+
### Help Browsers and Keyboards Fill the Field
|
|
554
|
+
|
|
555
|
+
Set `type`, `inputMode`, and `autoComplete` on `TextInput.Control` to select the on-screen keyboard and enable saved values.
|
|
556
|
+
|
|
557
|
+
* **Email (email):** Set `type="email"` and `autoComplete="email"`.
|
|
558
|
+
* **Name (name):** Set `autoComplete="name"`.
|
|
559
|
+
* **URL or Webhook (url):** Set `type="url"` and `autoComplete="url"`.
|
|
560
|
+
* **Search (search):** Set `type="search"`.
|
|
561
|
+
* **0x Address (off):** Turn off autofill, capitalizing, and spellcheck.
|
|
562
|
+
* **Numeric Code (numeric):** Set `inputMode="numeric"` and turn off autofill.
|
|
563
|
+
|
|
564
|
+
Avoid `type="number"` for amounts and identifiers. It drops leading zeros, accepts `e`, and some browsers change the value on scroll.
|
|
565
|
+
|
|
566
|
+
For labels, descriptions, errors, and validation timing, see [Field](/docs/components/field).
|
|
567
|
+
|
|
568
|
+
## Accessibility
|
|
569
|
+
|
|
570
|
+
An input renders a native `<input>` inside a styled group. Inside a `Field.Root`, it links to the label, description, and error. See [Accessibility](/docs/foundations/accessibility) for the baseline.
|
|
571
|
+
|
|
572
|
+
### Semantics
|
|
573
|
+
|
|
574
|
+
* **TextInput.Control (textbox):** A native input whose role follows its type.
|
|
575
|
+
* **TextInput.Group (div):** Has no role of its own.
|
|
576
|
+
* **Invalid and Success (aria-invalid):** `invalid` sets `aria-invalid`. `success` sets no ARIA state.
|
|
577
|
+
* **TextInput.Prefix and TextInput.Suffix:** Plain text, such as "$" or "USDC". Not part of the input's name.
|
|
578
|
+
* **TextInput.Clear (button):** Labelled "Clear". Its hit area extends past its circle.
|
|
579
|
+
|
|
580
|
+
### Keyboard
|
|
581
|
+
|
|
582
|
+
* **Move to the TextInput (Tab):** Moves focus to the input, then to the clear button when shown.
|
|
583
|
+
* **Clear the TextInput (Enter or Space):** On the clear button, empties the input and returns focus to it.
|
|
584
|
+
* **Clear Before Closing (Escape):** With a clear button, Escape empties a filled input first.
|
|
585
|
+
|
|
586
|
+
All other keys follow the native input.
|
|
587
|
+
|
|
588
|
+
### Size and Motion
|
|
589
|
+
|
|
590
|
+
* **Target Size (48px):** Every field is 48px tall, above the 24px WCAG 2.2 minimum.
|
|
591
|
+
* **Reduced Motion (reduce):** Under reduced motion, the nudge and pop don't play.
|
|
592
|
+
|
|
593
|
+
### Your Responsibilities
|
|
594
|
+
|
|
595
|
+
* **Label Every TextInput (Field.Label):** Use a visible label, or an `aria-label` when none fits. A prefix icon doesn't name it.
|
|
596
|
+
* **Name the Unit:** If the unit matters, put it in the label or description, such as "Amount in USDC".
|
|
597
|
+
* **Declare the Purpose (autoComplete):** Set it with `type` and `inputMode` to declare the field's purpose. WCAG requires it for personal data.
|
|
598
|
+
* **Explain Invalid Values (Field.Error):** Don't rely on the red fill alone. Explain an invalid value in text, such as "Enter an amount above 0".
|
|
599
|
+
|
|
600
|
+
## Related
|
|
601
|
+
|
|
602
|
+
[Field](/docs/components/field)
|
|
603
|
+
|
|
604
|
+
Use for labels, descriptions, and errors.
|
|
605
|
+
|
|
606
|
+
[AmountInput](/docs/components/amount-input)
|
|
607
|
+
|
|
608
|
+
Use for token and fiat amounts.
|
|
609
|
+
|
|
610
|
+
[Textarea](/docs/components/textarea)
|
|
611
|
+
|
|
612
|
+
Use for multi-line text.
|
|
613
|
+
|
|
614
|
+
[Combobox](/docs/components/combobox)
|
|
615
|
+
|
|
616
|
+
Use for picking from a long list by typing.
|
|
617
|
+
|
|
618
|
+
[Forms](/docs/patterns/forms)
|
|
619
|
+
|
|
620
|
+
Covers laying out fields and actions.
|
|
621
|
+
|
|
622
|
+
[Errors and Validation](/docs/patterns/errors-and-validation)
|
|
623
|
+
|
|
624
|
+
Covers when and where to show errors.
|