An accessible hover card component for React with controllable state, configurable delays, keyboard navigation, and full ARIA compliance
npx @tessl/cli install tessl/npm-radix-ui--react-hover-card@1.1.0An 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.
npm install @radix-ui/react-hover-cardimport {
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");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>
);
}The hover card system is built on several key concepts:
HoverCard manages the overall state and provides contextHoverCardTrigger detects hover/focus events and anchors positioningHoverCardPortal renders content outside normal DOM hierarchyHoverCardContent handles positioning, interactions, and accessibilitycreateHoverCardScope enables nested hover card isolationThe 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>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 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>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>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>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>
);
}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>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>
);
}<HoverCard openDelay={1000} closeDelay={500}>
<HoverCardTrigger>Slow to open, quick to close</HoverCardTrigger>
<HoverCardContent>Content with custom timing</HoverCardContent>
</HoverCard>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>
);
}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);
}Components automatically receive data attributes for styling based on their state:
data-state="open" - Applied to HoverCardTrigger and HoverCardContent when the hover card is opendata-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;
}Supports all modern browsers including:
^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc (hooks support required)^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc