tsimport {XDSHoverCard} from '@xds/core/HoverCard'
| Guidance | Practices |
|---|---|
| Do | Keep content supplementary — hover cards should enhance understanding without blocking the primary workflow. |
| Do | Provide a dashed underline on text triggers so users know the element is hoverable. |
| Do | Use the hook API (useXDSHoverCard) when you need more control over timing or placement. |
| Don't | Place critical actions or required information inside a hover card — users may miss content that only appears on hover. |
| Don't | Use a hover card when a simple Tooltip or Popover would suffice. |
| Don't | Use a HoverCard for content the user must interact with — it disappears when the cursor leaves. |
| Prop | Type | Description |
|---|---|---|
contentrequired | ReactNode | Hover card content. |
children | ReactNode | Trigger element that must accept a ref. |
placement | LayerPlacement (default: 'above') | Position relative to the anchor element. |
alignment | LayerAlignment (default: 'center') | Alignment along the placement axis. |
delay | number (default: 300) | Show delay in milliseconds. |
hideDelay | number (default: 200) | Hide delay in milliseconds. |
focusTrigger | 'auto' | 'always' | 'never' (default: 'auto') | Controls when focus events trigger the hover card. |
isEnabled | boolean (default: true) | Enables or disables the hover and focus triggers. |
onOpenChange | (isOpen: boolean) => void | Callback fired when hover card visibility changes. Called with true when shown and false when hidden. |
hasHoverIndication | 'auto' | boolean (default: 'auto') | Shows a dashed underline on the trigger element. |
isDefaultOpen | boolean | Whether the hover card should be shown on mount. Still dismissible. |
tsx'use client';import * as stylex from '@stylexjs/stylex';import {XDSHoverCard} from '@xds/core/HoverCard';import {XDSVStack} from '@xds/core/Layout';import {XDSText} from '@xds/core/Text';const styles = stylex.create({content: {maxWidth: 200},});export default function HoverCardInlineTextHoverCard() {return (<XDSText type="body">The component uses a{' '}<XDSHoverCardcontent={<XDSVStack gap={1} xstyle={styles.content}><XDSText type="label">Focus trap</XDSText><XDSText type="body" color="secondary">A pattern that keeps keyboard focus inside a container, preventingit from moving to elements outside. Used in dialogs and modals toensure accessibility.</XDSText></XDSVStack>}placement="above">focus trap</XDSHoverCard>{' '}to keep keyboard navigation inside the{' '}<XDSHoverCardcontent={<XDSVStack gap={1} xstyle={styles.content}><XDSText type="label">Modal dialog</XDSText><XDSText type="body" color="secondary">An overlay that blocks interaction with the rest of the page untilthe user responds. Uses the native HTML dialog element forbuilt-in accessibility and backdrop support.</XDSText></XDSVStack>}placement="above">modal dialog</XDSHoverCard>.</XDSText>);}
tsx'use client';import * as stylex from '@stylexjs/stylex';import {XDSHoverCard} from '@xds/core/HoverCard';import {XDSIcon} from '@xds/core/Icon';import {XDSVStack, XDSHStack} from '@xds/core/Layout';import {XDSText} from '@xds/core/Text';import {LinkIcon} from '@heroicons/react/24/outline';const styles = stylex.create({content: {maxWidth: 280},});export default function HoverCardInteractiveContent() {return (<XDSText type="body">Read more in the{' '}<XDSHoverCardplacement="below"content={<XDSVStack gap={2} xstyle={styles.content}><XDSHStack gap={2} vAlign="start"><XDSIcon icon={LinkIcon} size="sm" color="secondary" /><XDSVStack gap={1}><XDSText type="label">Getting Started Guide</XDSText><XDSText type="body" color="secondary">Learn how to set up your first project, invite team members,and configure your workspace.</XDSText><XDSText type="supporting" color="secondary">docs.example.com/getting-started</XDSText></XDSVStack></XDSHStack></XDSVStack>}>Getting Started Guide</XDSHoverCard>.</XDSText>);}
tsx'use client';import * as stylex from '@stylexjs/stylex';import {XDSHoverCard} from '@xds/core/HoverCard';import {XDSAvatar} from '@xds/core/Avatar';import {XDSButton} from '@xds/core/Button';import {XDSIcon} from '@xds/core/Icon';import {XDSVStack, XDSHStack} from '@xds/core/Layout';import {XDSText, XDSHeading} from '@xds/core/Text';import {CalendarIcon} from '@heroicons/react/24/outline';const styles = stylex.create({avatar: {flexShrink: 0},content: {maxWidth: 280},});export default function HoverCardProfileHoverCard() {return (<XDSHoverCardplacement="below"content={<XDSHStack gap={3} vAlign="start" xstyle={styles.content}><XDSAvatar name="Jane Doe" size={48} xstyle={styles.avatar} /><XDSVStack gap={1}><XDSHeading level={3}>@janedoe</XDSHeading><XDSText type="body" color="secondary">Crafting accessible, scalable design systems for modern teams.</XDSText><XDSHStack gap={1} vAlign="center"><XDSIcon icon={CalendarIcon} size="xsm" color="secondary" /><XDSText type="supporting" color="secondary">March 2024</XDSText></XDSHStack></XDSVStack></XDSHStack>}><XDSButton label="@janedoe" variant="ghost" /></XDSHoverCard>);}
tsx'use client';import {XDSHoverCard} from '@xds/core/HoverCard';import {XDSButton} from '@xds/core/Button';import {XDSStack} from '@xds/core/Layout';import {XDSText, XDSHeading} from '@xds/core/Text';import {XDSAvatar} from '@xds/core/Avatar';import * as stylex from '@stylexjs/stylex';const styles = stylex.create({card: {width: 240,},});export default function HoverCardShowcase() {return (<XDSHoverCardplacement="above"isDefaultOpencontent={<XDSStack direction="vertical" gap={2} xstyle={styles.card}><XDSStack direction="horizontal" gap={2} vAlign="center"><XDSAvatar name="Jane Doe" size="medium" /><XDSStack direction="vertical" gap={0}><XDSHeading level={5}>Jane Doe</XDSHeading><XDSText type="supporting" color="secondary">Software Engineer</XDSText></XDSStack></XDSStack><XDSText type="body" color="secondary">Building great products with great people.</XDSText></XDSStack>}><XDSButton label="@janedoe" variant="ghost" /></XDSHoverCard>);}