tsimport {XDSButton} from '@xds/core/Button'
| Guidance | Practices |
|---|---|
| Do | Reserve primary for the single most important action in the view. Use secondary or ghost for everything else based on emphasis. |
| Do | Write labels that describe the action — "Save changes", "Delete account", "Send invite" — not vague labels like "OK" or "Click here". |
| Do | Show a loading state for actions that take time, like saving or submitting, so the user knows it is working. |
| Do | Always provide a label for icon-only buttons so screen readers can announce what the button does. Add a tooltip for sighted users. |
| Don't | Place more than one primary button in the same view — this dilutes the visual hierarchy. |
| Don't | Use the destructive variant without a confirmation step for irreversible actions like deleting data. |
| Don't | Use a button for navigation — if it only takes the user to another page, use a link instead. Buttons are for actions like saving, deleting, or submitting. |
tsx'use client';import {XDSButton} from '@xds/core/Button';import {XDSBadge} from '@xds/core/Badge';import {XDSStack} from '@xds/core/Layout';import {XDSText} from '@xds/core/Text';export default function ButtonWithEndSlot() {return (<XDSStack direction="vertical" gap={4}><XDSText type="supporting" color="secondary">Trailing badges for counts or status</XDSText><XDSStack direction="horizontal" gap={3} vAlign="center"><XDSButtonlabel="Messages"variant="primary"endContent={<XDSBadge variant="info" label={3} />}/><XDSButtonlabel="Notifications"variant="secondary"endContent={<XDSBadge variant="warning" label={12} />}/><XDSButtonlabel="Updates"variant="ghost"endContent={<XDSBadge variant="neutral" label="New" />}/></XDSStack></XDSStack>);}
tsx'use client';import {XDSButton} from '@xds/core/Button';import {XDSIcon} from '@xds/core/Icon';import {XDSStack} from '@xds/core/Layout';import {XDSText} from '@xds/core/Text';import {ArrowDownTrayIcon,PencilSquareIcon,PlusIcon,TrashIcon,} from '@heroicons/react/24/outline';export default function ButtonWithIcon() {return (<XDSStack direction="vertical" gap={4}><XDSText type="supporting" color="secondary">Icons reinforce the action</XDSText><XDSStack direction="horizontal" gap={3} vAlign="center"><XDSButtonlabel="New item"variant="primary"icon={<XDSIcon icon={PlusIcon} />}/><XDSButtonlabel="Edit"variant="secondary"icon={<XDSIcon icon={PencilSquareIcon} />}/><XDSButtonlabel="Download"variant="ghost"icon={<XDSIcon icon={ArrowDownTrayIcon} />}/><XDSButtonlabel="Delete"variant="destructive"icon={<XDSIcon icon={TrashIcon} />}/></XDSStack></XDSStack>);}
tsx'use client';import {XDSButton} from '@xds/core/Button';import {XDSStack} from '@xds/core/Layout';import {XDSText} from '@xds/core/Text';const SIZES = [{size: 'sm' as const, label: 'Small'},{size: 'md' as const, label: 'Medium'},{size: 'lg' as const, label: 'Large'},];export default function ButtonSizeVariants() {return (<XDSStack direction="vertical" gap={4}><XDSStack direction="vertical" gap={1}><XDSText type="supporting" color="secondary">Primary</XDSText><XDSStack direction="horizontal" gap={3} vAlign="center">{SIZES.map(({size, label}) => (<XDSButton key={size} label={label} variant="primary" size={size} />))}</XDSStack></XDSStack><XDSStack direction="vertical" gap={1}><XDSText type="supporting" color="secondary">Secondary</XDSText><XDSStack direction="horizontal" gap={3} vAlign="center">{SIZES.map(({size, label}) => (<XDSButtonkey={size}label={label}variant="secondary"size={size}/>))}</XDSStack></XDSStack></XDSStack>);}
tsx'use client';import {XDSButton} from '@xds/core/Button';import {XDSStack} from '@xds/core/Layout';import {XDSText} from '@xds/core/Text';const VARIANTS = [{variant: 'primary' as const, label: 'Primary'},{variant: 'secondary' as const, label: 'Secondary'},{variant: 'ghost' as const, label: 'Ghost'},{variant: 'destructive' as const, label: 'Destructive'},];export default function ButtonVariants() {return (<XDSStack direction="vertical" gap={4}><XDSStack direction="vertical" gap={1}><XDSText type="supporting" color="secondary">Default</XDSText><XDSStack direction="horizontal" gap={3} vAlign="center">{VARIANTS.map(({variant, label}) => (<XDSButton key={variant} label={label} variant={variant} />))}</XDSStack></XDSStack><XDSStack direction="vertical" gap={1}><XDSText type="supporting" color="secondary">Disabled</XDSText><XDSStack direction="horizontal" gap={3} vAlign="center">{VARIANTS.map(({variant, label}) => (<XDSButtonkey={variant}label={label}variant={variant}isDisabled/>))}</XDSStack></XDSStack><XDSStack direction="vertical" gap={1}><XDSText type="supporting" color="secondary">Loading</XDSText><XDSStack direction="horizontal" gap={3} vAlign="center">{VARIANTS.map(({variant, label}) => (<XDSButtonkey={variant}label={label}variant={variant}isLoading/>))}</XDSStack></XDSStack></XDSStack>);}
tsx'use client';import {XDSButton} from '@xds/core/Button';import {XDSStack} from '@xds/core/Layout';export default function ButtonShowcase() {return (<XDSStack direction="horizontal" gap={3} vAlign="center"><XDSButton label="Primary" variant="primary" /><XDSButton label="Secondary" variant="secondary" /><XDSButton label="Ghost" variant="ghost" /><XDSButton label="Destructive" variant="destructive" /></XDSStack>);}