HoverCard
Install: npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1
Version and compatibility
Pinned Mantine Core 9.7.1 requires React and React DOM ^19.2.0 and matching @mantine/hooks@9.7.1, from the installed npm package's peerDependencies. Do not force it into React 18 or another incompatible version. Explain upgrade impact and agree on a plan with the project owner; do not hide conflicts with --force/--legacy-peer-deps. The native Provider enables theme.respectReducedMotion and uses forceColorScheme for light/dark.
Use case
Show contextual content around a hover target.
Native props used by this example
These props are extracted from the local typechecked JSX and grouped by their owning native component. This is not an exhaustive prop list; see pinned source signatures and inheritance below.
This minimal example passes children only; no additional props are invented. Optional props are in the source reference.
Interaction and state checks
Current scenarios: Default. Check actual behavior after selecting supported disabled/error/read-only scenarios; components without those native states do not receive invented universal props. Verify keyboard focus and exits, then connect changed values through the native callback signature.
Business integration boundary
Demo content/state is local, without server persistence, authorization or fetching. A static display component is not a completed business workflow.
Host setup
Install pinned @mantine/core and @mantine/hooks, import @mantine/core/styles.css at the entry and use MantineProvider. The example's theme/variant are JGuang-authored host props, not universal native component APIs; forceColorScheme synchronizes the app theme. Native implementation source is a reading reference: use npm exports rather than copying internal engines. This batch covers Core, not dates/charts/forms extension packages. Detailed upstream prose remains English.
Runnable usage
import { useState } from 'react';
import * as M from '@mantine/core';
import '@mantine/core/styles.css';
function ComponentPreview({ variant = 'Default' }: { variant?: string }) {
const content = <M.Text>Build something beautiful / 构建美好的界面</M.Text>;
return <M.HoverCard><M.HoverCard.Target><M.Button>Hover me</M.Button></M.HoverCard.Target><M.HoverCard.Dropdown>{content}</M.HoverCard.Dropdown></M.HoverCard>;
}
export default function Example({ variant = 'Default', theme = 'light' }: { variant?: string; theme?: 'light' | 'dark' }) {
return <M.MantineProvider forceColorScheme={theme} theme={{ respectReducedMotion: true }}><ComponentPreview variant={variant} /></M.MantineProvider>;
}
Preview states
Default
The example uses the native Mantine API. For supported input demos, change the local variant to Disabled, Invalid or Read only; these are example labels, not new component props. Keep the documented data, controlled values, stores and compound children when adapting the example.
Usage
Delays
Set open and close delays in ms with the openDelay and closeDelay props:
HoverCard delay group
Use the HoverCard.Group component to sync open and close delays of multiple HoverCard components:
Activation events
The events prop determines which interactions open the dropdown. Fields that are not specified
keep their default values, for example events={{ focus: false }} disables focus activation
and leaves hover activation enabled:
<DataTable head={['Field', 'Default', 'Description']} data={[ [<code>hover</code>, <code>true</code>, 'Dropdown is opened when the target is hovered with a mouse'], [<code>focus</code>, <code>true</code>, 'Dropdown is opened when the target is focused with the keyboard'], [ <code>touch</code>, <code>false</code>, <> Dropdown is opened when the target is tapped on a touch device, requires <code>hover</code>{' '} to be enabled </>, ], ]} />
Focus activation uses :focus-visible semantics: the dropdown is opened when the target is focused with the keyboard, but not when it is focused by a mouse click.
touch is disabled by default because there is no hover on touch devices – the first tap would
open the dropdown instead of activating the target. Enable it only if the target does not have its
own tap action. touch extends hover activation, it has no effect if hover is disabled.
Keyboard interactions
<DataTable head={['Key', 'Description']} data={[ ['Tab', <>Moves focus to the target, opens the dropdown if <code>events.focus</code> is enabled</>], ['Escape', <>Closes the dropdown, can be disabled with <code>{'closeOnEscape={false}'}</code></>], ]} />
The dropdown is also closed when the user presses outside of the target and the dropdown
(pointerdown event), set closeOnClickOutside={false} to disable this behavior. Note that the
clickOutsideEvents prop is not supported by HoverCard: outside press is always detected with
the pointerdown event.
Interactive dropdown
By default, the dropdown is closed as soon as the pointer leaves the target: if there is a gap between the target and the dropdown, or if the pointer travels diagonally over unrelated elements, the dropdown closes before the pointer reaches it.
Set the interactive prop to keep the dropdown open while the pointer travels toward it. It is
required by WCAG 1.4.13
if the dropdown contains interactive content. Note that an interactive dropdown intercepts pointer
events of the content it overlaps:
With interactive elements
HoverCard is displayed only when the mouse is over the target element or dropdown.
You can use anchors and buttons within dropdowns, using inputs is not recommended:
Dropdown role
The role prop controls the accessible relation between the target and the dropdown:
<DataTable head={['Value', 'Target attributes', 'Dropdown attributes']} data={[ [ <> <code>dialog</code> (default) </>, <> <code>aria-haspopup="dialog"</code>, <code>aria-expanded</code>, <code>aria-controls</code> </>, <> <code>role="dialog"</code>, <code>aria-labelledby</code> </>, ], [<code>tooltip</code>, <code>aria-describedby</code>, <code>role="tooltip"</code>], ]} />
Use role="tooltip" if the dropdown contains only descriptive content – its content is then
announced by screen readers as the description of the target.
Keep the default role="dialog" if the dropdown contains headings, links, buttons or any other
content that is not a plain description of the target.
Accessibility
HoverCard can be opened with a mouse and with the keyboard, and is announced by screen readers:
- The target is focusable if it is an interactive element (a button or a link). If the target is
not interactive, add
tabIndex={0}to it to make it reachable with the keyboard. - Focusing the target with the keyboard opens the dropdown,
Escapeand a press outside of the target and the dropdown close it. onDismissis called when the dropdown is closed withEscapekey or with a press outside of the target and the dropdown.aria-haspopup,aria-expanded,aria-controlsandaria-describedbyattributes are managed by the component, see the Dropdown role section.- The
returnFocusprop is ignored while focus activation is enabled (events.focus, the default): focus is already on the target when the dropdown is opened with the keyboard, and returning it after the target was blurred would trap keyboard users on the target.Escapepressed inside the dropdown always returns focus to the target.
Limitations
The dropdown is rendered in a portal at the end of document.body, it is not a part of the tab
order of the page. Keyboard users can open, read and dismiss the dropdown, but cannot move focus
into it – links and buttons inside the dropdown are not reachable with the keyboard.
If the dropdown contains interactive content, that content must also be available elsewhere on the
page. Do not use the trapFocus prop to work around this limitation: focus cannot be moved into
the dropdown in the first place, and trapping focus in a hover-triggered element strands keyboard
users.
With withinPortal={false} the dropdown is rendered next to the target and focus can be moved into
it with Tab, but moving focus out of the dropdown with Tab does not close it – the dropdown is
closed with Escape, with a press outside or when the pointer leaves the target.
Hover and focus activations do not coordinate: if the pointer leaves the target while the target is
focused with the keyboard, the dropdown is closed after closeDelay and is not reopened until the
target is blurred and focused again.
Source-backed parameter reference
Implementation signatures and types are generated from the pinned local source. Optional props, native inherited types, union branches and never exclusions are preserved. A forwardRef implementation's ref is a React reference, not an additional business prop.
HoverCard(props: HoverCardProps)
export interface HoverCardEvents {
/** Determines whether the dropdown should be opened when the target is hovered @default true */
hover?: boolean;
/** Determines whether the dropdown should be opened when the target is focused with the keyboard @default true */
focus?: boolean;
/** Determines whether the dropdown should be opened when the target is tapped on touch devices. Requires `hover` to be enabled @default false */
touch?: boolean;
}
export interface HoverCardProps extends Omit<PopoverProps, 'opened' | 'onChange'> {
/** Initial opened state */
initiallyOpened?: boolean;
/** Called when the dropdown is opened */
onOpen?: () => void;
/** Called when the dropdown is closed */
onClose?: () => void;
/**
* Delay in ms before the dropdown opens after mouse enters the target.
* Overridden by HoverCard.Group delay if used within a group.
* @default 0
*/
openDelay?: number;
/**
* Delay in ms before the dropdown closes after mouse leaves the target or dropdown.
* Overridden by HoverCard.Group delay if used within a group.
* @default 150
*/
closeDelay?: number;
/**
* Determines which events open the dropdown. Fields that are not specified keep their default values.
* @default { hover: true, focus: true, touch: false }
*/
events?: HoverCardEvents;
/**
* If set, the dropdown stays open while the pointer travels from the target to the dropdown
* and remains over it. Set it if the dropdown contains interactive content.
* @default false
*/
interactive?: boolean;
/**
* Accessible relation between the target and the dropdown. `dialog` sets `aria-haspopup`,
* `aria-expanded` and `aria-controls` on the target, `tooltip` sets `aria-describedby` instead
* and should be used if the dropdown contains only descriptive content.
* @default 'dialog'
*/
role?: 'dialog' | 'tooltip';
/** Determines whether the dropdown should be closed when the user presses outside of the target and the dropdown @default true */
closeOnClickOutside?: boolean;
/** Not supported by `HoverCard`: outside press is always detected with the `pointerdown` event. Use `closeOnClickOutside` to disable it. */
clickOutsideEvents?: string[];
/**
* Determines whether focus should be returned to the target when the dropdown closes.
* Ignored when focus activation is enabled (`events.focus`, the default), otherwise moving
* focus away from the target would return it and reopen the dropdown.
* `Escape` pressed inside the dropdown always returns focus to the target.
* @default false
*/
returnFocus?: boolean;
/** Called when the dropdown is closed with `Escape` key or with a press outside of the target and the dropdown */
onDismiss?: () => void;
}
Native and external types
External types remain defined by React or native dependencies, not manually expanded into guessed props. The installed version's TypeScript definitions are authoritative.
Omit<PopoverProps, 'opened' | 'onChange'>
PopoverProps