@mshafiqyajid/react-hover-card
Headless hover card hook and styled component. Mouse and keyboard triggered, smart auto-placement, open/close delay timers, portal positioning, arrow, flip + shift, dark mode, reduced-motion safe.
Playground #
Props
TSX
import { HoverCardStyled } from "@mshafiqyajid/react-hover-card/styled";
import "@mshafiqyajid/react-hover-card/styles.css";
<HoverCardStyled
content="Hover card content"
/>Install #
npm install @mshafiqyajid/react-hover-card Quick start #
import { HoverCardStyled } from "@mshafiqyajid/react-hover-card/styled";
import "@mshafiqyajid/react-hover-card/styles.css";
<HoverCardStyled
content={
<div>
<strong>@username</strong>
<p>Joined January 2024 ยท 120 followers</p>
</div>
}
openDelay={300}
placement="auto"
>
<a href="/profile">@username</a>
</HoverCardStyled> Headless #
import { useHoverCard } from "@mshafiqyajid/react-hover-card";
const { triggerProps, cardProps, isOpen, open, close } = useHoverCard({
openDelay: 300,
closeDelay: 100,
onOpenChange: (open) => console.log("open:", open),
});
return (
<>
<a href="/profile" {...triggerProps}>@username</a>
{isOpen && (
<div {...cardProps} className="my-card">
<p>Rich content here</p>
</div>
)}
</>
); The hook handles open/close timers, keyboard (Escape), and ARIA. Position the card with your own layout or portal solution.
API โ HoverCardStyled #
| Prop | Type | Default | Description |
|---|---|---|---|
| content | ReactNode | โ | Card body content |
| children | ReactElement | โ | The trigger element |
| openDelay | number | 300 | ms before opening on hover/focus |
| closeDelay | number | 100 | ms before closing after mouse-leave/blur |
| placement | "auto" | "top" | "bottom" | "left" | "right" (each with optional -start / -end) | "auto" | Preferred placement; auto picks the side with most room |
| offset | number | 8 | Gap in px between trigger and card |
| collisionPadding | number | 8 | Viewport edge margin for flip/shift |
| flip | boolean | true | Auto-flip to opposite side near edges |
| shift | boolean | true | Push back into view along cross-axis |
| arrow | boolean | true | Show arrow pointing to trigger |
| strategy | "absolute" | "fixed" | "absolute" | Positioning strategy |
| open | boolean | โ | Controlled open state |
| defaultOpen | boolean | false | Initial open state (uncontrolled) |
| onOpenChange | (open: boolean) => void | โ | Callback when open state changes |
| className | string | โ | Extra class on the card element |
| style | React.CSSProperties | โ | Inline styles on the card element |
API โ useHoverCard #
| Option | Type | Default | Description |
|---|---|---|---|
| openDelay | number | 300 | ms before opening |
| closeDelay | number | 100 | ms before closing |
| open | boolean | โ | Controlled open state |
| defaultOpen | boolean | false | Initial open state (uncontrolled) |
| onOpenChange | (open: boolean) => void | โ | Callback on open state change |
Returns: triggerProps, cardProps, isOpen, open(), close()
CSS variables #
| Variable | Default | Description |
|---|---|---|
| --rhc-bg | #ffffff | Card background |
| --rhc-fg | #18181b | Card text color |
| --rhc-border | #e4e4e7 | Card border color |
| --rhc-radius | 10px | Card border radius |
| --rhc-shadow | โ | Card box shadow |
| --rhc-duration-in | 180ms | Open transition duration |
| --rhc-duration-out | 120ms | Close transition duration |
| --rhc-min-width | 220px | Minimum card width |
| --rhc-max-width | 360px | Maximum card width |
| --rhc-padding | 1rem | Content padding |
data-placement #
The card's data-placement attribute reflects the resolved (post-flip) placement. Style side-specific arrow direction or radius by it.