CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-radix-ui--react-hover-card

An accessible hover card component for React with controllable state, configurable delays, keyboard navigation, and full ARIA compliance

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

Radix UI React Hover Card

An accessible hover card component for React applications that displays rich content when users hover over a trigger element. Built with full accessibility compliance, keyboard navigation support, controllable state, and configurable delays.

Package Information

  • Package Name: @radix-ui/react-hover-card
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @radix-ui/react-hover-card

Core Imports

import {
  HoverCard,
  HoverCardTrigger,
  HoverCardContent,
  HoverCardPortal,
  HoverCardArrow,
  createHoverCardScope,
} from "@radix-ui/react-hover-card";

Alternative shorter imports using aliases:

import {
  Root,
  Trigger,
  Content,
  Portal,
  Arrow,
} from "@radix-ui/react-hover-card";

For CommonJS:

const {
  HoverCard,
  HoverCardTrigger,
  HoverCardContent,
  HoverCardPortal,
  HoverCardArrow,
} = require("@radix-ui/react-hover-card");

Basic Usage

import {
  HoverCard,
  HoverCardTrigger,
  HoverCardContent,
  HoverCardPortal,
} from "@radix-ui/react-hover-card";

function Example() {
  return (
    <HoverCard>
      <HoverCardTrigger asChild>
        <a
          href="https://twitter.com/radix_ui"
          target="_blank"
          rel="noreferrer noopener"
        >
          @radix_ui
        </a>
      </HoverCardTrigger>
      <HoverCardPortal>
        <HoverCardContent className="HoverCardContent" sideOffset={5}>
          <div style={{ display: "flex", flexDirection: "column", gap: 7 }}>
            <img
              src="https://pbs.twimg.com/profile_images/1337055608613253126/r_eiMp2H_400x400.png"
              alt="Radix UI"
              style={{ width: 45, height: 45, borderRadius: "50%" }}
            />
            <div style={{ display: "flex", flexDirection: "column", gap: 15 }}>
              <div>
                <div style={{ fontSize: 15, fontWeight: 500, color: "white" }}>
                  Radix
                </div>
                <div style={{ fontSize: 15, color: "#666" }}>@radix_ui</div>
              </div>
              <div style={{ fontSize: 14, color: "#999" }}>
                Components, icons, colors, and templates for building
                high‑quality, accessible UI. Free & open source.
              </div>
            </div>
          </div>
        </HoverCardContent>
      </HoverCardPortal>
    </HoverCard>
  );
}

Architecture

The hover card system is built on several key concepts:

  • Root Component: HoverCard manages the overall state and provides context
  • Trigger Component: HoverCardTrigger detects hover/focus events and anchors positioning
  • Portal System: HoverCardPortal renders content outside normal DOM hierarchy
  • Content Component: HoverCardContent handles positioning, interactions, and accessibility
  • Context Scoping: createHoverCardScope enables nested hover card isolation
  • Event Handling: Comprehensive pointer and keyboard event management with touch exclusion
  • Accessibility: Full ARIA compliance with dismissable layer integration

Capabilities

Root Component

The main hover card component that provides context and manages state.

interface HoverCardProps {
  children?: React.ReactNode;
  open?: boolean;
  defaultOpen?: boolean;
  onOpenChange?: (open: boolean) => void;
  openDelay?: number; // Default: 700ms
  closeDelay?: number; // Default: 300ms
}

declare const HoverCard: React.FC<HoverCardProps>;

Usage Example:

<HoverCard
  openDelay={500}
  closeDelay={200}
  onOpenChange={(open) => console.log('Hover card is', open ? 'open' : 'closed')}
>
  {/* trigger and content components */}
</HoverCard>

Trigger Component

The element that triggers the hover card when hovered or focused.

type HoverCardTriggerElement = React.ComponentRef<typeof Primitive.a>;
type PrimitiveLinkProps = React.ComponentPropsWithoutRef<typeof Primitive.a>;

interface HoverCardTriggerProps extends PrimitiveLinkProps {}

declare const HoverCardTrigger: React.ForwardRefExoticComponent<
  HoverCardTriggerProps & React.RefAttributes<HoverCardTriggerElement>
>;

Usage Example:

<HoverCardTrigger asChild>
  <button>Hover me</button>
</HoverCardTrigger>

Portal Component

Portal component for rendering content in a different part of the DOM tree.

interface HoverCardPortalProps {
  children?: React.ReactNode;
  /**
   * Specify a container element to portal the content into.
   */
  container?: Element | null;
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
}

declare const HoverCardPortal: React.FC<HoverCardPortalProps>;

Usage Example:

<HoverCardPortal container={document.getElementById('hover-cards')}>
  <HoverCardContent>Content here</HoverCardContent>
</HoverCardPortal>

Content Component

The content container with positioning, interaction handling, and accessibility features.

type HoverCardContentElement = React.ComponentRef<typeof PopperPrimitive.Content>;
type DismissableLayerProps = React.ComponentPropsWithoutRef<typeof DismissableLayer>;
type PopperContentProps = React.ComponentPropsWithoutRef<typeof PopperPrimitive.Content>;

interface HoverCardContentProps extends Omit<PopperContentProps, 'onPlaced'> {
  /**
   * Used to force mounting when more control is needed. Useful when
   * controlling animation with React animation libraries.
   */
  forceMount?: true;
  /**
   * Event handler called when the escape key is down.
   * Can be prevented.
   */
  onEscapeKeyDown?: DismissableLayerProps['onEscapeKeyDown'];
  /**
   * Event handler called when the a `pointerdown` event happens outside of the `HoverCard`.
   * Can be prevented.
   */
  onPointerDownOutside?: DismissableLayerProps['onPointerDownOutside'];
  /**
   * Event handler called when the focus moves outside of the `HoverCard`.
   * Can be prevented.
   */
  onFocusOutside?: DismissableLayerProps['onFocusOutside'];
  /**
   * Event handler called when an interaction happens outside the `HoverCard`.
   * Specifically, when a `pointerdown` event happens outside or focus moves outside of it.
   * Can be prevented.
   */
  onInteractOutside?: DismissableLayerProps['onInteractOutside'];
}

declare const HoverCardContent: React.ForwardRefExoticComponent<
  HoverCardContentProps & React.RefAttributes<HoverCardContentElement>
>;

Usage Example:

<HoverCardContent
  side="top"
  align="center"
  sideOffset={5}
  onEscapeKeyDown={(event) => {
    console.log('Escape pressed');
    // Prevent default to keep open
    // event.preventDefault();
  }}
>
  <div>Rich content here</div>
</HoverCardContent>

Arrow Component

Optional arrow element that points from the content to the trigger.

type HoverCardArrowElement = React.ComponentRef<typeof PopperPrimitive.Arrow>;
type PopperArrowProps = React.ComponentPropsWithoutRef<typeof PopperPrimitive.Arrow>;

interface HoverCardArrowProps extends PopperArrowProps {}

declare const HoverCardArrow: React.ForwardRefExoticComponent<
  HoverCardArrowProps & React.RefAttributes<HoverCardArrowElement>
>;

Usage Example:

<HoverCardContent>
  <HoverCardArrow className="HoverCardArrow" />
  <div>Content with arrow</div>
</HoverCardContent>

Context Scoping

Creates a scoped context for hover card components to prevent conflicts in nested scenarios.

declare const createHoverCardScope: () => {
  scopeHoverCard: (scope: any) => any;
};

Usage Example:

const { scopeHoverCard } = createHoverCardScope();

function NestedHoverCard() {
  return (
    <HoverCard __scopeHoverCard={scopeHoverCard}>
      <HoverCardTrigger __scopeHoverCard={scopeHoverCard}>
        Trigger
      </HoverCardTrigger>
      <HoverCardContent __scopeHoverCard={scopeHoverCard}>
        Content
      </HoverCardContent>
    </HoverCard>
  );
}

Component Aliases

For convenience, the package exports shorter aliases for all components:

declare const Root: typeof HoverCard;
declare const Trigger: typeof HoverCardTrigger;
declare const Portal: typeof HoverCardPortal;
declare const Content: typeof HoverCardContent;
declare const Arrow: typeof HoverCardArrow;

Usage Example:

import { Root, Trigger, Content, Portal } from "@radix-ui/react-hover-card";

<Root>
  <Trigger>Hover me</Trigger>
  <Portal>
    <Content>Content</Content>
  </Portal>
</Root>

Advanced Usage Patterns

Controlled State

function ControlledHoverCard() {
  const [open, setOpen] = React.useState(false);
  
  return (
    <HoverCard open={open} onOpenChange={setOpen}>
      <HoverCardTrigger>
        Controlled trigger (open: {open.toString()})
      </HoverCardTrigger>
      <HoverCardContent>
        <button onClick={() => setOpen(false)}>Close</button>
      </HoverCardContent>
    </HoverCard>
  );
}

Custom Delays

<HoverCard openDelay={1000} closeDelay={500}>
  <HoverCardTrigger>Slow to open, quick to close</HoverCardTrigger>
  <HoverCardContent>Content with custom timing</HoverCardContent>
</HoverCard>

Animation Integration

import * as React from "react";
import { HoverCard, HoverCardContent, HoverCardPortal, HoverCardTrigger } from "@radix-ui/react-hover-card";

function AnimatedHoverCard() {
  return (
    <HoverCard>
      <HoverCardTrigger>Animated trigger</HoverCardTrigger>
      <HoverCardPortal forceMount>
        <HoverCardContent
          forceMount
          className="data-[state=open]:animate-fadeIn data-[state=closed]:animate-fadeOut"
        >
          Content with CSS animations
        </HoverCardContent>
      </HoverCardPortal>
    </HoverCard>
  );
}

Accessibility Features

  • ARIA Compliance: Full ARIA labeling and role management
  • Keyboard Navigation: Tab, Escape, and arrow key support
  • Focus Management: Automatic focus handling and restoration
  • Screen Reader Support: Proper announcements and descriptions
  • Touch Device Support: Touch events are excluded to prevent conflicts
  • High Contrast: Compatible with high contrast modes and themes

CSS Custom Properties

The hover card components expose CSS custom properties that can be used for styling and positioning:

/* Available on HoverCardContent */
--radix-hover-card-content-transform-origin: var(--radix-popper-transform-origin);
--radix-hover-card-content-available-width: var(--radix-popper-available-width);
--radix-hover-card-content-available-height: var(--radix-popper-available-height);
--radix-hover-card-trigger-width: var(--radix-popper-anchor-width);
--radix-hover-card-trigger-height: var(--radix-popper-anchor-height);

These properties are automatically set by the positioning system and can be used in CSS for responsive styling:

.HoverCardContent {
  width: var(--radix-hover-card-trigger-width);
  max-width: var(--radix-hover-card-content-available-width);
  transform-origin: var(--radix-hover-card-content-transform-origin);
}

Data Attributes

Components automatically receive data attributes for styling based on their state:

  • data-state="open" - Applied to HoverCardTrigger and HoverCardContent when the hover card is open
  • data-state="closed" - Applied to HoverCardTrigger and HoverCardContent when the hover card is closed
.HoverCardTrigger[data-state="open"] {
  background-color: var(--hover-active);
}

.HoverCardContent[data-state="open"] {
  animation: slideIn 200ms ease-out;
}

Browser Support

Supports all modern browsers including:

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

Peer Dependencies

  • React: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc (hooks support required)
  • React DOM: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
  • @types/react: Optional TypeScript definitions
  • @types/react-dom: Optional TypeScript definitions

Install with Tessl CLI

npx tessl i tessl/npm-radix-ui--react-hover-card
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@radix-ui/react-hover-card@1.1.x
Publish Source
CLI
Badge
tessl/npm-radix-ui--react-hover-card badge