# How to Use Tooltip and HoverCard Overlay Components in Astryx

> Learn to use Astryx Tooltip and HoverCard overlay components for interactive content and text hints. Master placement and focus management in this technical guide.

- Repository: [Meta/astryx](https://github.com/facebook/astryx)
- Tags: how-to-guide
- Published: 2026-07-14

---

**Astryx provides two complementary overlay components—Tooltip for brief, non-interactive text hints and HoverCard for rich, interactive content—both built on the shared `useLayer` infrastructure with standardized placement APIs and WCAG-compliant focus management.**

The facebook/astryx repository includes a robust design system with advanced overlay primitives for React applications. Understanding the architectural differences between Tooltip and HoverCard ensures you render accessible, performant user interfaces that handle focus management and positioning correctly.

## Tooltip vs HoverCard: Key Differences

Astryx distinguishes these components by content type and interactivity requirements:

- **Tooltip**: Designed for short, static text labels (e.g., icon descriptions, button hints). It renders content in a portal and supports an optional dashed underline via the `hasHoverIndication` prop for text-only children.
- **HoverCard**: Built for richer, interactive content (e.g., profile cards, action menus). Unlike Tooltip, it renders an inline-safe floating layer that remains in the DOM flow, ensuring focusable elements inside stay reachable via keyboard navigation.

Both components share the same **LayerPlacement** and **LayerAlignment** props (e.g., `above`, `below`, `right`) and support controlled state via `isOpen`, `isDefaultOpen`, and `onOpenChange`. They also allow external anchoring through the `anchorRef` prop for sibling-mode positioning.

## Core Architecture and Source Files

Understanding the underlying hooks clarifies when to choose each component:

**`useTooltip`** (source: [`packages/core/src/Tooltip/useTooltip.tsx`](https://github.com/facebook/astryx/blob/main/packages/core/src/Tooltip/useTooltip.tsx)) supplies a `ref` to the trigger element, generates `aria-describedby` attributes for accessibility, and returns a `renderTooltip` function that creates the floating element.

**`Tooltip`** (source: [`packages/core/src/Tooltip/Tooltip.tsx`](https://github.com/facebook/astryx/blob/main/packages/core/src/Tooltip/Tooltip.tsx)) composes `useTooltip` and decides whether to render inline (as a `<span>`) for text-only children or wrap element children in a `display:contents` container to preserve refs.

**`useHoverCard`** (source: [`packages/core/src/HoverCard/useHoverCard.tsx`](https://github.com/facebook/astryx/blob/main/packages/core/src/HoverCard/useHoverCard.tsx)) acts as a thin wrapper around the core layer system. Crucially, it does **not** portal the layer, keeping the floating card in-document for interactive content.

**`HoverCard`** (source: [`packages/core/src/HoverCard/HoverCard.tsx`](https://github.com/facebook/astryx/blob/main/packages/core/src/HoverCard/HoverCard.tsx)) wraps `useHoverCard` and renders the trigger together with the card content via `renderHoverCard`.

Both hooks expose a **focus trigger** parameter (`auto`, `always`, `never`) that determines keyboard focus interactions, making them suitable for complex composite widgets.

## Implementation Examples

### Basic Tooltip with Button Trigger

Use Tooltip for simple text hints that appear after the default 200ms delay.

```tsx
import {Tooltip} from '@astryxdesign/core/Tooltip';
import {Button} from '@astryxdesign/core/Button';

function ExampleTooltip() {
  return (
    <Tooltip content="Save your changes" placement="above">
      <Button>Save</Button>
    </Tooltip>
  );
}

```

The tooltip accepts `delay`, `hideDelay`, and `focusTrigger` props to customize timing and keyboard behavior.

### Tooltip with External Anchor (Sibling Mode)

When you need to attach a tooltip to a sibling element rather than wrapping it as a child, use the `anchorRef` prop.

```tsx
import {Tooltip} from '@astryxdesign/core/Tooltip';
import {useRef} from 'react';

function ExternalAnchor() {
  const ref = useRef<HTMLDivElement>(null);

  return (
    <>
      <div ref={ref}>Hover over me</div>
      <Tooltip anchorRef={ref} content="External anchor tooltip" />
    </>
  );
}

```

In this mode, `Tooltip` renders as a sibling of the referenced element and requires no children.

### Interactive HoverCard with Profile Content

Use HoverCard when the overlay contains interactive controls like buttons or links that must remain focusable.

```tsx
import {HoverCard} from '@astryxdesign/core/HoverCard';
import {Avatar} from '@astryxdesign/core/Avatar';
import {Button} from '@astryxdesign/core/Button';

function ProfileCard({user}) {
  return (
    <div style={{padding: 12}}>
      <Avatar src={user.avatar} alt={user.name} />
      <h4>{user.name}</h4>
      <Button onClick={() => alert('Message sent')}>Message</Button>
    </div>
  );
}

function ExampleHoverCard() {
  return (
    <HoverCard content={<ProfileCard user={myUser} />} placement="right">
      <span>John Doe</span>
    </HoverCard>
  );
}

```

Because HoverCard does not portal the layer, inner controls stay reachable via Tab navigation without being reparented in the DOM.

### HoverCard with External Anchor Reference

Similar to Tooltip, HoverCard supports external anchoring via `anchorRef` for layouts where wrapping is not feasible.

```tsx
import {HoverCard} from '@astryxdesign/core/HoverCard';
import {useRef} from 'react';

function AnchorHoverCard() {
  const ref = useRef<HTMLDivElement>(null);
  return (
    <>
      <div ref={ref}>Hover over this area</div>
      <HoverCard anchorRef={ref} content={<p>Additional info</p>} />
    </>
  );
}

```

## Summary

- **Tooltip** handles brief, non-interactive text hints and renders content through a portal, with optional hover indication for text-only triggers.
- **HoverCard** manages rich, interactive overlays that remain in the document flow, ensuring focusable elements stay accessible.
- Both components utilize the `useLayer` infrastructure in `packages/core/src/` and support standardized placement, alignment, and controlled state APIs.
- Use `anchorRef` for sibling-mode positioning when you cannot wrap the trigger element directly.
- Configure `focusTrigger` and delay props to fine-tune accessibility and interaction timing.

## Frequently Asked Questions

### What is the difference between Tooltip and HoverCard in Astryx?

Tooltip is optimized for short, static text labels without interactive elements, rendering content in a portal with optional hover indication. HoverCard is designed for richer content containing buttons, links, or complex layouts that must stay in the DOM flow to remain focusable and interactive.

### Can HoverCard contain interactive elements like buttons?

Yes. Unlike Tooltip, HoverCard renders its layer inline rather than in a portal, which keeps interactive elements like buttons and links in the natural tab order. This is implemented in [`packages/core/src/HoverCard/useHoverCard.tsx`](https://github.com/facebook/astryx/blob/main/packages/core/src/HoverCard/useHoverCard.tsx) to ensure the floating card stays inside the DOM flow.

### How do I control the open state programmatically?

Both Tooltip and HoverCard support controlled state via three props: `isOpen` for full control, `isDefaultOpen` for initial state, and `onOpenChange` for change callbacks. These props allow integration with parent state management or external events.

### Where are the useTooltip and useHoverCard hooks implemented?

The `useTooltip` hook is located at [`packages/core/src/Tooltip/useTooltip.tsx`](https://github.com/facebook/astryx/blob/main/packages/core/src/Tooltip/useTooltip.tsx) and manages positioning, delays, focus handling, and ARIA attributes. The `useHoverCard` hook is found at [`packages/core/src/HoverCard/useHoverCard.tsx`](https://github.com/facebook/astryx/blob/main/packages/core/src/HoverCard/useHoverCard.tsx) and provides similar functionality but without portal reparenting, making it suitable for interactive content.