Morphing Popover
NewInstallation
npx shadcn@latest add https://uibrik.com/r/morphing-popover.jsonInstall the packages
npm install motionAdd the cn helper
Imports
cnfrom@/lib/utils, whichshadcn initcreates. Add it by hand without shadcn.Copy the source into your project
components/uibrik/morphing-popover/morphing-popover.tsx"use client"; import { useEffect, useLayoutEffect, useRef, useState, type ReactNode } from "react"; import { AnimatePresence, MotionConfig, motion } from "motion/react"; import { cn } from "@/lib/utils"; // Morphing popover. A button that grows into a panel and folds back into the // button. It's one surface throughout: its real width, height and corner // radius spring between the button's size and the panel's, so nothing is ever // scaled and text, borders and shadow stay crisp. The panel's content is laid // out at full width from the start and revealed as the surface grows over it, // fading in once there's room. The panel stays pinned to one corner of the // button, and when its content changes size (a form swapped for a thank-you) // the surface springs to the new height. // // Escape, a click outside or `close()` from the content folds it back. Focus // moves into the panel on open and back to the button on close. export type MorphingPopoverOrigin = "top-left" | "top-right" | "bottom-left" | "bottom-right"; export type MorphingPopoverProps = { /** Text of the button, and the panel's title. */ label?: string; /** What's inside the panel. A function receives `close`. */
Adds the files to
components/uibrik/morphing-popover and installs motion. With the @uibrik namespace set up: npx shadcn@latest add @uibrik/morphing-popover.Props
MorphingPopover- origin
- Type "top-left" | "top-right" | "bottom-left" | "bottom-right"
- "top-left"
- Corner of the button the panel stays pinned to as it grows.
- width
- Type number
- 340
- Width of the open panel.
- duration
- Type number
- 0.5
- How long the morph takes.
- bounce
- Type number
- 0.1
- Springiness of the morph. 0 settles without overshoot.
- childrenrequired
- Type ReactNode | (close) => ReactNode
- –
- What's inside the panel. Mark a field with data-autofocus to focus it on open.
- label
- Type string
- "Feedback"
- Text of the button, and the panel's title.
- open / onOpenChange
- Type boolean / (open) => void
- –
- Controlled open state.
- className
- Type string
- –
- Classes for the surface.
- panelClassName
- Type string
- –
- Classes for the panel's content box (padded by default).