tsimport {XDSField} from '@xds/core/Field'
| Guidance | Practices |
|---|---|
| Do | Always provide a label for accessibility, even if visually hidden with isLabelHidden. |
| Do | Use the status prop with clear messages to provide inline validation feedback. |
| Do | Add a description when the label alone does not explain what the field expects, like format hints or constraints. |
| Don't | Set both isOptional and isRequired on the same field. |
| Don't | Use the detached status variant on bordered inputs — reserve it for checkboxes, switches, and sliders. |
| Don't | Hide the label without providing an alternative way for the user to understand the field purpose. |
| Prop | Type | Description |
|---|---|---|
labelrequired | string | Label text for the field (always rendered for accessibility). |
inputIDrequired | string | ID for the input element (used for the label htmlFor attribute). |
childrenrequired | ReactNode | The input or control to render. |
isLabelHidden | boolean (default: false) | Visually hide the label (still accessible to screen readers). |
isDisabled | boolean (default: false) | Whether the associated input is disabled. Propagates disabled styling to the label. |
description | string | Description text displayed between the label and input. |
descriptionID | string | ID for the description element (use for aria-describedby on the input). |
isOptional | boolean (default: false) | Whether the field is optional (mutually exclusive with isRequired). |
isRequired | boolean (default: false) | Whether the field is required (mutually exclusive with isOptional). |
labelIcon | XDSIconType | Icon to display before the label text. See `npx xds docs icons` for valid semantic names. |
labelTooltip | string | Tooltip text to display in an info icon at the end of the label. |
status | XDSFieldStatus | Status indicator with type and optional message. When message is set, displays a colored status box. |
statusVariant | 'attached' | 'detached' (default: 'attached') | How the status message renders relative to the input. Attached overlaps the input border; detached floats below. |
ref | React.Ref<HTMLDivElement> | Ref forwarded to the root element. |
xstyle | StyleXStyles | StyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value — not an inline style object like style={{}}. |
className | string | CSS class name(s) appended to the root element. Prefer xstyle for StyleX deduplication. |
style | React.CSSProperties | Inline styles applied to the root element. Takes priority over StyleX inline styles. |
| Prop | Type | Description |
|---|---|---|
labelrequired | string | Label text. |
inputIDrequired | string | ID of the input this label is for. |
isLabelHidden | boolean (default: false) | Visually hide the label. |
isDisabled | boolean (default: false) | Whether the associated input is disabled. |
isOptional | boolean (default: false) | Show "Optional" indicator. |
isRequired | boolean (default: false) | Show "Required" indicator. |
labelIcon | XDSIconType | Icon before the label text. See `npx xds docs icons` for valid semantic names. |
labelTooltip | string | Tooltip text for info icon at end of label. |
| Prop | Type | Description |
|---|---|---|
typerequired | 'error' | 'warning' | 'success' | Status type. |
messagerequired | string | Status message text. |
id | string | ID for aria-describedby association. |
variant | 'attached' | 'detached' (default: 'attached') | Visual variant — attached overlaps the input, detached floats below. |
tsx'use client';import {useState} from 'react';import {XDSTextInput} from '@xds/core/TextInput';import {XDSVStack} from '@xds/core/Layout';import {XDSCenter} from '@xds/core/Center';export default function FieldWithDescription() {const [email, setEmail] = useState('');const [password, setPassword] = useState('');return (<XDSCenter><XDSVStack gap={4}><XDSTextInputlabel="Email"description="We'll send a confirmation link to this address"value={email}onChange={setEmail}placeholder="you@example.com"/><XDSTextInputlabel="Password"description="At least 8 characters with one uppercase letter"value={password}onChange={setPassword}placeholder="Create a password"/></XDSVStack></XDSCenter>);}
tsx'use client';import {useState} from 'react';import {XDSTextInput} from '@xds/core/TextInput';import {XDSVStack} from '@xds/core/Layout';import {XDSCenter} from '@xds/core/Center';export default function FieldRequired() {const [username, setUsername] = useState('');const [email, setEmail] = useState('');return (<XDSCenter><XDSVStack gap={4}><XDSTextInputlabel="Username"isRequiredvalue={username}onChange={setUsername}placeholder="Enter your username"/><XDSTextInputlabel="Backup email"isOptionalvalue={email}onChange={setEmail}placeholder="you@example.com"/></XDSVStack></XDSCenter>);}
tsx'use client';import {useState} from 'react';import {XDSTextInput} from '@xds/core/TextInput';import {XDSVStack} from '@xds/core/Layout';import {XDSCenter} from '@xds/core/Center';export default function FieldStatusVariants() {const [email, setEmail] = useState('bad-email');const [username, setUsername] = useState('admin');const [apiKey, setApiKey] = useState('sk-live-abc123');return (<XDSCenter><XDSVStack gap={4}><XDSTextInputlabel="Email"description="Enter your work email"value={email}onChange={setEmail}status={{type: 'error',message: 'Please enter a valid email address',}}/><XDSTextInputlabel="Username"description="Choose a unique username"value={username}onChange={setUsername}status={{type: 'warning',message: 'This username is reserved for administrators',}}/><XDSTextInputlabel="API Key"description="Paste your API key"value={apiKey}onChange={setApiKey}status={{type: 'success', message: 'API key is valid and active'}}/></XDSVStack></XDSCenter>);}
tsx'use client';import {useState} from 'react';import {XDSField} from '@xds/core/Field';import {XDSTextInput} from '@xds/core/TextInput';import {XDSStack} from '@xds/core/Layout';import * as stylex from '@stylexjs/stylex';const styles = stylex.create({root: {width: 320,},});export default function FieldShowcase() {const [email, setEmail] = useState('');const status =email.length > 0 && !email.includes('@')? {type: 'error' as const, message: 'Enter a valid email address.'}: undefined;return (<XDSStack direction="vertical" gap={3} xstyle={styles.root}><XDSFieldlabel="Email"inputID="field-email"description="We will never share your email."isRequiredstatus={status}><XDSTextInputlabel="Email"isLabelHiddenvalue={email}onChange={setEmail}placeholder="you@example.com"/></XDSField></XDSStack>);}