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.00
# Radix UI React Hover Card
1
2
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.
3
4
## Package Information
5
6
- **Package Name**: @radix-ui/react-hover-card
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install @radix-ui/react-hover-card`
10
11
## Core Imports
12
13
```typescript
14
import {
15
HoverCard,
16
HoverCardTrigger,
17
HoverCardContent,
18
HoverCardPortal,
19
HoverCardArrow,
20
createHoverCardScope,
21
} from "@radix-ui/react-hover-card";
22
```
23
24
Alternative shorter imports using aliases:
25
26
```typescript
27
import {
28
Root,
29
Trigger,
30
Content,
31
Portal,
32
Arrow,
33
} from "@radix-ui/react-hover-card";
34
```
35
36
For CommonJS:
37
38
```javascript
39
const {
40
HoverCard,
41
HoverCardTrigger,
42
HoverCardContent,
43
HoverCardPortal,
44
HoverCardArrow,
45
} = require("@radix-ui/react-hover-card");
46
```
47
48
## Basic Usage
49
50
```typescript
51
import {
52
HoverCard,
53
HoverCardTrigger,
54
HoverCardContent,
55
HoverCardPortal,
56
} from "@radix-ui/react-hover-card";
57
58
function Example() {
59
return (
60
<HoverCard>
61
<HoverCardTrigger asChild>
62
<a
63
href="https://twitter.com/radix_ui"
64
target="_blank"
65
rel="noreferrer noopener"
66
>
67
@radix_ui
68
</a>
69
</HoverCardTrigger>
70
<HoverCardPortal>
71
<HoverCardContent className="HoverCardContent" sideOffset={5}>
72
<div style={{ display: "flex", flexDirection: "column", gap: 7 }}>
73
<img
74
src="https://pbs.twimg.com/profile_images/1337055608613253126/r_eiMp2H_400x400.png"
75
alt="Radix UI"
76
style={{ width: 45, height: 45, borderRadius: "50%" }}
77
/>
78
<div style={{ display: "flex", flexDirection: "column", gap: 15 }}>
79
<div>
80
<div style={{ fontSize: 15, fontWeight: 500, color: "white" }}>
81
Radix
82
</div>
83
<div style={{ fontSize: 15, color: "#666" }}>@radix_ui</div>
84
</div>
85
<div style={{ fontSize: 14, color: "#999" }}>
86
Components, icons, colors, and templates for building
87
high‑quality, accessible UI. Free & open source.
88
</div>
89
</div>
90
</div>
91
</HoverCardContent>
92
</HoverCardPortal>
93
</HoverCard>
94
);
95
}
96
```
97
98
## Architecture
99
100
The hover card system is built on several key concepts:
101
102
- **Root Component**: `HoverCard` manages the overall state and provides context
103
- **Trigger Component**: `HoverCardTrigger` detects hover/focus events and anchors positioning
104
- **Portal System**: `HoverCardPortal` renders content outside normal DOM hierarchy
105
- **Content Component**: `HoverCardContent` handles positioning, interactions, and accessibility
106
- **Context Scoping**: `createHoverCardScope` enables nested hover card isolation
107
- **Event Handling**: Comprehensive pointer and keyboard event management with touch exclusion
108
- **Accessibility**: Full ARIA compliance with dismissable layer integration
109
110
## Capabilities
111
112
### Root Component
113
114
The main hover card component that provides context and manages state.
115
116
```typescript { .api }
117
interface HoverCardProps {
118
children?: React.ReactNode;
119
open?: boolean;
120
defaultOpen?: boolean;
121
onOpenChange?: (open: boolean) => void;
122
openDelay?: number; // Default: 700ms
123
closeDelay?: number; // Default: 300ms
124
}
125
126
declare const HoverCard: React.FC<HoverCardProps>;
127
```
128
129
**Usage Example:**
130
131
```typescript
132
<HoverCard
133
openDelay={500}
134
closeDelay={200}
135
onOpenChange={(open) => console.log('Hover card is', open ? 'open' : 'closed')}
136
>
137
{/* trigger and content components */}
138
</HoverCard>
139
```
140
141
### Trigger Component
142
143
The element that triggers the hover card when hovered or focused.
144
145
```typescript { .api }
146
type HoverCardTriggerElement = React.ComponentRef<typeof Primitive.a>;
147
type PrimitiveLinkProps = React.ComponentPropsWithoutRef<typeof Primitive.a>;
148
149
interface HoverCardTriggerProps extends PrimitiveLinkProps {}
150
151
declare const HoverCardTrigger: React.ForwardRefExoticComponent<
152
HoverCardTriggerProps & React.RefAttributes<HoverCardTriggerElement>
153
>;
154
```
155
156
**Usage Example:**
157
158
```typescript
159
<HoverCardTrigger asChild>
160
<button>Hover me</button>
161
</HoverCardTrigger>
162
```
163
164
### Portal Component
165
166
Portal component for rendering content in a different part of the DOM tree.
167
168
```typescript { .api }
169
interface HoverCardPortalProps {
170
children?: React.ReactNode;
171
/**
172
* Specify a container element to portal the content into.
173
*/
174
container?: Element | null;
175
/**
176
* Used to force mounting when more control is needed. Useful when
177
* controlling animation with React animation libraries.
178
*/
179
forceMount?: true;
180
}
181
182
declare const HoverCardPortal: React.FC<HoverCardPortalProps>;
183
```
184
185
**Usage Example:**
186
187
```typescript
188
<HoverCardPortal container={document.getElementById('hover-cards')}>
189
<HoverCardContent>Content here</HoverCardContent>
190
</HoverCardPortal>
191
```
192
193
### Content Component
194
195
The content container with positioning, interaction handling, and accessibility features.
196
197
```typescript { .api }
198
type HoverCardContentElement = React.ComponentRef<typeof PopperPrimitive.Content>;
199
type DismissableLayerProps = React.ComponentPropsWithoutRef<typeof DismissableLayer>;
200
type PopperContentProps = React.ComponentPropsWithoutRef<typeof PopperPrimitive.Content>;
201
202
interface HoverCardContentProps extends Omit<PopperContentProps, 'onPlaced'> {
203
/**
204
* Used to force mounting when more control is needed. Useful when
205
* controlling animation with React animation libraries.
206
*/
207
forceMount?: true;
208
/**
209
* Event handler called when the escape key is down.
210
* Can be prevented.
211
*/
212
onEscapeKeyDown?: DismissableLayerProps['onEscapeKeyDown'];
213
/**
214
* Event handler called when the a `pointerdown` event happens outside of the `HoverCard`.
215
* Can be prevented.
216
*/
217
onPointerDownOutside?: DismissableLayerProps['onPointerDownOutside'];
218
/**
219
* Event handler called when the focus moves outside of the `HoverCard`.
220
* Can be prevented.
221
*/
222
onFocusOutside?: DismissableLayerProps['onFocusOutside'];
223
/**
224
* Event handler called when an interaction happens outside the `HoverCard`.
225
* Specifically, when a `pointerdown` event happens outside or focus moves outside of it.
226
* Can be prevented.
227
*/
228
onInteractOutside?: DismissableLayerProps['onInteractOutside'];
229
}
230
231
declare const HoverCardContent: React.ForwardRefExoticComponent<
232
HoverCardContentProps & React.RefAttributes<HoverCardContentElement>
233
>;
234
```
235
236
**Usage Example:**
237
238
```typescript
239
<HoverCardContent
240
side="top"
241
align="center"
242
sideOffset={5}
243
onEscapeKeyDown={(event) => {
244
console.log('Escape pressed');
245
// Prevent default to keep open
246
// event.preventDefault();
247
}}
248
>
249
<div>Rich content here</div>
250
</HoverCardContent>
251
```
252
253
### Arrow Component
254
255
Optional arrow element that points from the content to the trigger.
256
257
```typescript { .api }
258
type HoverCardArrowElement = React.ComponentRef<typeof PopperPrimitive.Arrow>;
259
type PopperArrowProps = React.ComponentPropsWithoutRef<typeof PopperPrimitive.Arrow>;
260
261
interface HoverCardArrowProps extends PopperArrowProps {}
262
263
declare const HoverCardArrow: React.ForwardRefExoticComponent<
264
HoverCardArrowProps & React.RefAttributes<HoverCardArrowElement>
265
>;
266
```
267
268
**Usage Example:**
269
270
```typescript
271
<HoverCardContent>
272
<HoverCardArrow className="HoverCardArrow" />
273
<div>Content with arrow</div>
274
</HoverCardContent>
275
```
276
277
### Context Scoping
278
279
Creates a scoped context for hover card components to prevent conflicts in nested scenarios.
280
281
```typescript { .api }
282
declare const createHoverCardScope: () => {
283
scopeHoverCard: (scope: any) => any;
284
};
285
```
286
287
**Usage Example:**
288
289
```typescript
290
const { scopeHoverCard } = createHoverCardScope();
291
292
function NestedHoverCard() {
293
return (
294
<HoverCard __scopeHoverCard={scopeHoverCard}>
295
<HoverCardTrigger __scopeHoverCard={scopeHoverCard}>
296
Trigger
297
</HoverCardTrigger>
298
<HoverCardContent __scopeHoverCard={scopeHoverCard}>
299
Content
300
</HoverCardContent>
301
</HoverCard>
302
);
303
}
304
```
305
306
## Component Aliases
307
308
For convenience, the package exports shorter aliases for all components:
309
310
```typescript { .api }
311
declare const Root: typeof HoverCard;
312
declare const Trigger: typeof HoverCardTrigger;
313
declare const Portal: typeof HoverCardPortal;
314
declare const Content: typeof HoverCardContent;
315
declare const Arrow: typeof HoverCardArrow;
316
```
317
318
**Usage Example:**
319
320
```typescript
321
import { Root, Trigger, Content, Portal } from "@radix-ui/react-hover-card";
322
323
<Root>
324
<Trigger>Hover me</Trigger>
325
<Portal>
326
<Content>Content</Content>
327
</Portal>
328
</Root>
329
```
330
331
## Advanced Usage Patterns
332
333
### Controlled State
334
335
```typescript
336
function ControlledHoverCard() {
337
const [open, setOpen] = React.useState(false);
338
339
return (
340
<HoverCard open={open} onOpenChange={setOpen}>
341
<HoverCardTrigger>
342
Controlled trigger (open: {open.toString()})
343
</HoverCardTrigger>
344
<HoverCardContent>
345
<button onClick={() => setOpen(false)}>Close</button>
346
</HoverCardContent>
347
</HoverCard>
348
);
349
}
350
```
351
352
### Custom Delays
353
354
```typescript
355
<HoverCard openDelay={1000} closeDelay={500}>
356
<HoverCardTrigger>Slow to open, quick to close</HoverCardTrigger>
357
<HoverCardContent>Content with custom timing</HoverCardContent>
358
</HoverCard>
359
```
360
361
### Animation Integration
362
363
```typescript
364
import * as React from "react";
365
import { HoverCard, HoverCardContent, HoverCardPortal, HoverCardTrigger } from "@radix-ui/react-hover-card";
366
367
function AnimatedHoverCard() {
368
return (
369
<HoverCard>
370
<HoverCardTrigger>Animated trigger</HoverCardTrigger>
371
<HoverCardPortal forceMount>
372
<HoverCardContent
373
forceMount
374
className="data-[state=open]:animate-fadeIn data-[state=closed]:animate-fadeOut"
375
>
376
Content with CSS animations
377
</HoverCardContent>
378
</HoverCardPortal>
379
</HoverCard>
380
);
381
}
382
```
383
384
## Accessibility Features
385
386
- **ARIA Compliance**: Full ARIA labeling and role management
387
- **Keyboard Navigation**: Tab, Escape, and arrow key support
388
- **Focus Management**: Automatic focus handling and restoration
389
- **Screen Reader Support**: Proper announcements and descriptions
390
- **Touch Device Support**: Touch events are excluded to prevent conflicts
391
- **High Contrast**: Compatible with high contrast modes and themes
392
393
## CSS Custom Properties
394
395
The hover card components expose CSS custom properties that can be used for styling and positioning:
396
397
```css
398
/* Available on HoverCardContent */
399
--radix-hover-card-content-transform-origin: var(--radix-popper-transform-origin);
400
--radix-hover-card-content-available-width: var(--radix-popper-available-width);
401
--radix-hover-card-content-available-height: var(--radix-popper-available-height);
402
--radix-hover-card-trigger-width: var(--radix-popper-anchor-width);
403
--radix-hover-card-trigger-height: var(--radix-popper-anchor-height);
404
```
405
406
These properties are automatically set by the positioning system and can be used in CSS for responsive styling:
407
408
```css
409
.HoverCardContent {
410
width: var(--radix-hover-card-trigger-width);
411
max-width: var(--radix-hover-card-content-available-width);
412
transform-origin: var(--radix-hover-card-content-transform-origin);
413
}
414
```
415
416
## Data Attributes
417
418
Components automatically receive data attributes for styling based on their state:
419
420
- `data-state="open"` - Applied to HoverCardTrigger and HoverCardContent when the hover card is open
421
- `data-state="closed"` - Applied to HoverCardTrigger and HoverCardContent when the hover card is closed
422
423
```css
424
.HoverCardTrigger[data-state="open"] {
425
background-color: var(--hover-active);
426
}
427
428
.HoverCardContent[data-state="open"] {
429
animation: slideIn 200ms ease-out;
430
}
431
```
432
433
## Browser Support
434
435
Supports all modern browsers including:
436
- Chrome (latest)
437
- Firefox (latest)
438
- Safari (latest)
439
- Edge (latest)
440
441
## Peer Dependencies
442
443
- **React**: `^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc` (hooks support required)
444
- **React DOM**: `^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc`
445
- **@types/react**: Optional TypeScript definitions
446
- **@types/react-dom**: Optional TypeScript definitions