tsimport {XDSTextInput} from '@xds/core/TextInput'
| Guidance | Practices |
|---|---|
| Do | Always provide a visible label so users know what the field is for. Only hide the label when surrounding context makes it obvious, like a search bar with a magnifying-glass icon. |
| Do | Use validation status with a message to explain what went wrong — "Email must include @" is better than just turning the border red. |
| Do | Size the input to match the expected content length so users can gauge how much to type — small for zip codes, medium for names, large for URLs. |
| Do | Add a clear button for search and filter inputs so users can quickly reset without selecting all text. |
| Don't | Don't use placeholder text as a replacement for a label — placeholders disappear on focus and are not reliably read by screen readers. |
| Don't | Don't use TextInput for multi-line content like comments or descriptions — use TextArea instead. |
| Don't | Don't mark every field as required — only flag truly mandatory fields so users are not overwhelmed by validation errors. |
tsx'use client';import {useState} from 'react';import {XDSTextInput} from '@xds/core/TextInput';import {XDSStack} from '@xds/core/Layout';import {EnvelopeIcon,LockClosedIcon,UserIcon,} from '@heroicons/react/24/outline';export default function TextInputIcon() {const [name, setName] = useState('');const [email, setEmail] = useState('');const [password, setPassword] = useState('');return (<div style={{width: 300}}><XDSStack direction="vertical" gap={3}><XDSTextInputlabel="Full name"value={name}onChange={setName}placeholder="Sarah Chen"startIcon={UserIcon}/><XDSTextInputtype="email"label="Email"value={email}onChange={setEmail}placeholder="sarah@company.com"startIcon={EnvelopeIcon}/><XDSTextInputtype="password"label="Password"value={password}onChange={setPassword}placeholder="Enter your password"startIcon={LockClosedIcon}/></XDSStack></div>);}
tsx'use client';import {useState} from 'react';import {XDSTextInput} from '@xds/core/TextInput';import {XDSStack} from '@xds/core/Layout';import {MagnifyingGlassIcon} from '@heroicons/react/24/outline';export default function TextInputSearch() {const [query, setQuery] = useState('');const [filter, setFilter] = useState('design systems');return (<div style={{width: 300}}><XDSStack direction="vertical" gap={3}><XDSTextInputlabel="Search field"value={query}onChange={setQuery}placeholder="Search projects…"startIcon={MagnifyingGlassIcon}hasClear/><XDSTextInputlabel="Search field with value"value={filter}onChange={setFilter}placeholder="Filter…"startIcon={MagnifyingGlassIcon}hasClear/></XDSStack></div>);}
tsx'use client';import {useState} from 'react';import {XDSTextInput} from '@xds/core/TextInput';import {XDSStack} from '@xds/core/Layout';export default function TextInputSizes() {const [sm, setSm] = useState('');const [md, setMd] = useState('');const [lg, setLg] = useState('');return (<div style={{width: 300}}><XDSStack direction="vertical" gap={3}><XDSTextInputlabel="Small"value={sm}onChange={setSm}placeholder="Enter a value"size="sm"/><XDSTextInputlabel="Medium"value={md}onChange={setMd}placeholder="Enter a value"size="md"/><XDSTextInputlabel="Large"value={lg}onChange={setLg}placeholder="Enter a value"size="lg"/></XDSStack></div>);}
tsx'use client';import {useState} from 'react';import {XDSTextInput} from '@xds/core/TextInput';import {XDSStack} from '@xds/core/Layout';export default function TextInputStates() {const [error, setError] = useState('sarah@');const [warning, setWarning] = useState('sarah_chen');const [success, setSuccess] = useState('https://sarahchen.dev');const [errorOnly, setErrorOnly] = useState('test');return (<div style={{width: 300}}><XDSStack direction="vertical" gap={3}><XDSTextInputlabel="Error message"value={error}onChange={setError}placeholder="Enter a value"status={{type: 'error',message: 'Please enter a valid email address.',}}/><XDSTextInputlabel="Warning message"value={warning}onChange={setWarning}placeholder="Enter a value"status={{type: 'warning',message: 'This username is already taken — try adding a number.',}}/><XDSTextInputlabel="Success message"value={success}onChange={setSuccess}placeholder="Enter a value"status={{type: 'success', message: 'URL is valid and reachable.'}}/><XDSTextInputlabel="Status without message"value={errorOnly}onChange={setErrorOnly}placeholder="Enter a value"status={{type: 'error'}}/><XDSTextInputlabel="Disabled field"value=""onChange={() => {}}placeholder="Enter a value"isDisabled/><XDSTextInputlabel="Loading field"value="sarahc"onChange={() => {}}isLoading/></XDSStack></div>);}
tsx'use client';import {useState} from 'react';import {XDSTextInput} from '@xds/core/TextInput';import {XDSStack} from '@xds/core/Layout';export default function TextInputTypes() {const [password, setPassword] = useState('hunter42');const [email, setEmail] = useState('sarah@example.com');const [tooltip, setTooltip] = useState('');const [required, setRequired] = useState('');const [optional, setOptional] = useState('');const [described, setDescribed] = useState('');return (<div style={{width: 300}}><XDSStack direction="vertical" gap={3}><XDSTextInputlabel="Default field"value={described}onChange={setDescribed}placeholder="Enter your email"description="Descriptions can be used to provide additional information about a field."/><XDSTextInputtype="password"label="Password field"value={password}onChange={setPassword}placeholder="Enter a value"/><XDSTextInputtype="email"label="Email field"value={email}onChange={setEmail}placeholder="Enter a value"/><XDSTextInputlabel="Field tooltip"value={tooltip}onChange={setTooltip}placeholder="Enter your API key"labelTooltip="Your unique API key for authentication. Keep this secret!"/><XDSTextInputlabel="Required field"value={required}onChange={setRequired}placeholder="Enter your username"isRequired/><XDSTextInputlabel="Optional field"value={optional}onChange={setOptional}placeholder="Enter your nickname"isOptional/></XDSStack></div>);}
tsx'use client';import {XDSTextInput} from '@xds/core/TextInput';export default function TextInputShowcase() {return (<div style={{width: 300}}><XDSTextInputlabel="Name"value=""onChange={() => {}}placeholder="Enter your name"/></div>);}