Skip to content

feat: implement React HoverCard component using @base-ui/react primitives (#93)#293

Open
rabadiyameet073 wants to merge 1 commit into
rtCamp:mainfrom
rabadiyameet073:main
Open

feat: implement React HoverCard component using @base-ui/react primitives (#93)#293
rabadiyameet073 wants to merge 1 commit into
rtCamp:mainfrom
rabadiyameet073:main

Conversation

@rabadiyameet073

@rabadiyameet073 rabadiyameet073 commented Jun 30, 2026

Copy link
Copy Markdown
image image image
Frappe.UI.React.-.Video.mp4

Closes #93

Overview & Motivation

This PR implements the React version of the HoverCard component for the Frappe UI design system, following the behavior specified in the Frappe UI documentation (https://ui.frappe.io/docs/components/hovercard) and issue comment (#93 (comment)).

The component is built using @base-ui/react/preview-card primitives to maintain architectural consistency with existing headless components in frappe-ui-react.

File-by-File Technical Summary

  1. packages/frappe-ui-react/src/components/hoverCard/types.ts
  • Defined the TypeScript interface HoverCardProps supporting positioning (side, align, offset, collisionPadding), triggers (trigger, children), delays (hoverDelay, leaveDelay), portal overrides (portalTo), arrow toggle (arrow), and open state control handlers (open, defaultOpen, onOpenChange).
  1. packages/frappe-ui-react/src/components/hoverCard/hoverCard.tsx
  • Assembled the component structure using @base-ui/react/preview-card parts.
  • Mapped timing delay conversions (from seconds to milliseconds) directly onto the <PreviewCard.Trigger>.
  • Configured <PreviewCard.Portal> target containers dynamically based on the portalTo prop.
  • Rendered the arrow element <PreviewCard.Arrow> with a block display SVG and custom path to avoid rendering base separator lines.
  • Set up directional rotations on <PreviewCard.Arrow> using Tailwind selectors (data-[side]) to align the pointer toward the trigger.
  1. packages/frappe-ui-react/src/components/hoverCard/hoverCard.css
  • Added CSS keyframes (hovercard-in and hovercard-out) to animate scale and opacity.
  • Applied these transitions using the state data-attribute selectors [data-open] and [data-closed].
  • Implemented @media (prefers-reduced-motion: reduce) overrides to support system-level accessibility settings.
  1. packages/frappe-ui-react/src/components/hoverCard/index.ts
  • Exported the default HoverCard component and all typescript prop interfaces.
  1. packages/frappe-ui-react/src/components/index.ts
  • Added the wildcard export for ./hoverCard to register the new component globally in the component library.
  1. packages/frappe-ui-react/src/components/hoverCard/hoverCard.stories.tsx
  • Documented Default (@jane profile link), Delays (slow fade-in/fade-out), and Arrow (downward pointing arrow indicator) usage stories.
  • Omitted control mapping for complex objects and functions (trigger, children, portalTo, onOpenChange, open, defaultOpen) to ensure the control panel is clean and prevent Storybook iframe communication timeouts.
  1. packages/frappe-ui-react/src/components/hoverCard/tests/hoverCard.tsx
  • Implemented unit tests covering default hidden state rendering, mouse hover transitions (entering/exiting), and controlled open state synchronization.

Copilot AI review requested due to automatic review settings June 30, 2026 13:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements a new HoverCard component for the Frappe UI React design system, built on top of @base-ui/react/preview-card primitives, and wires it into the component barrel exports alongside Storybook stories, styles, and unit tests.

Changes:

  • Added HoverCard component implementation using Base UI PreviewCard primitives, including optional arrow rendering and timing delays.
  • Added HoverCard-specific animation CSS and Storybook stories demonstrating common usage.
  • Added initial unit tests and exported the component/types through the library’s index barrels.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/frappe-ui-react/src/components/index.ts Exposes the new hoverCard module from the main components barrel.
packages/frappe-ui-react/src/components/hoverCard/types.ts Introduces public prop/types for the new HoverCard API.
packages/frappe-ui-react/src/components/hoverCard/hoverCard.tsx Implements the HoverCard composition using @base-ui/react/preview-card.
packages/frappe-ui-react/src/components/hoverCard/hoverCard.css Adds open/close animations and reduced-motion overrides for the popup.
packages/frappe-ui-react/src/components/hoverCard/index.ts Barrel exports for the HoverCard component and its types.
packages/frappe-ui-react/src/components/hoverCard/hoverCard.stories.tsx Adds Storybook documentation/examples for HoverCard variants.
packages/frappe-ui-react/src/components/hoverCard/tests/hoverCard.tsx Adds unit tests for visibility behavior and controlled mode.

Comment on lines +22 to +28
const container = useMemo(() => {
if (typeof portalTo === "string") {
if (portalTo === "body") return document.body;
return document.querySelector(portalTo) as HTMLElement;
}
return portalTo;
}, [portalTo]);
Comment on lines +58 to +72
it("supports controlled mode via open and onOpenChange", async () => {
const onOpenChange = jest.fn();

const { rerender } = render(
<HoverCard
open={false}
onOpenChange={onOpenChange}
trigger={<button>Hover trigger</button>}
>
<div>Popup content</div>
</HoverCard>
);

expect(screen.queryByText("Popup content")).not.toBeInTheDocument();

Comment on lines +1 to +14
import type { ReactNode } from "react";

export type HoverCardSide = "top" | "right" | "bottom" | "left";
export type HoverCardAlign = "start" | "center" | "end";

export interface HoverCardProps {
/**
* The content to show inside the HoverCard popup.
*/
children?: ReactNode;
/**
* The trigger element that activates the HoverCard when hovered or focused.
*/
trigger: ReactNode;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create hoverCard component

2 participants