For the complete documentation index, see llms.txt. Markdown variants are available by appending .md to any URL or sending an Accept: text/markdown header. An agent skill is available at /.well-known/agent-skills/site-skill.md.
/
144
Sponsor

Popover

A popover/hover-card with fade, scale, and translate.

@alexsmith
Alex Smith@alexsmithProduct designer. Building in public.

Installation

$ pnpm dlx shadcn@latest add @framecn/popover

Usage

import { Popover } from "@/components/ui/popover";
<div style={{ position: "relative", display: "inline-block" }}>
  <button>@alexsmith</button>
  <div
    style={{
      position: "absolute",
      bottom: "calc(100% + 12px)",
      left: "50%",
      transform: "translateX(-50%)",
    }}
  >
    <Popover state="opened" side="top" width={240}>
      Hover-card content
    </Popover>
  </div>
</div>

Popover has no built-in trigger — position it relative to your anchor and supply children for custom content.

Smooth transitions

The docs preview eases a cursor onto an @username chip, opens a hover-card above it via usePopoverTransition, then closes as the cursor leaves:

import { H, W } from "@/lib/customizer-config";
import { Cursor } from "@/components/framecn/cursor";
import { useCursorPath } from "@/components/framecn/use-cursor-path";
import { Popover } from "@/components/framecn/popover";
import { usePopoverTransition } from "@/components/framecn/use-popover-transition";
 
const CHIP_X = W / 2;
const CHIP_Y = H / 2;
const AWAY_X = W / 2 - 440;
const AWAY_Y = H / 2 - 260;
 
const cursorStyle = useCursorPath([
  { at: 0, x: 80, y: 60 },
  { at: 28, x: CHIP_X, y: CHIP_Y, duration: 24 },
  { at: 110, x: AWAY_X, y: AWAY_Y, duration: 20 },
]);
 
const popoverStyle = usePopoverTransition([
  { at: 36, state: "opened", duration: 10 },
  { at: 100, state: "closed", duration: 10 },
]);
 
<div style={{ position: "relative", display: "inline-block" }}>
  @alexsmith
  <div style={{ position: "absolute", bottom: "calc(100% + 12px)", left: "50%", transform: "translateX(-50%)" }}>
    <Popover style={popoverStyle} side="top" width={240}>
      {/* hover-card content */}
    </Popover>
  </div>
</div>
<Cursor style={cursorStyle} variant="pointer" />;

Schedule the popover's opened step shortly after the cursor arrives on the anchor. style takes precedence over state when both are provided.

API Reference

Popover

PropTypeDefault
state"opened" | "closed""closed"
stylePopoverStyle- (takes precedence over state)
titlestring-
descriptionstring-
childrenReact.ReactNode-
side"top" | "bottom" | "left" | "right""bottom"
widthnumber288
themePartial<FramecnTheme>-
classNamestring-