Popover
Migration guide for Popover from HeroUI v2 to v3
Refer to the v3 Popover documentation for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.
Overview
The Popover component in HeroUI v3 has been redesigned with a compound component pattern, requiring explicit structure with Popover.Content, Popover.Dialog, Popover.Heading, and Popover.Arrow components.
Structure Changes
v2: Separate Components
In v2, Popover used separate components:
import { Popover, PopoverTrigger, PopoverContent } from "@heroui/react";
<Popover placement="right">
<PopoverTrigger>
<Button>Open</Button>
</PopoverTrigger>
<PopoverContent>
<div>Content</div>
</PopoverContent>
</Popover>v3: Compound Components
In v3, Popover uses compound components:
import { Popover, Button } from "@heroui/react";
<Popover>
<Button>Open</Button>
<Popover.Content>
<Popover.Dialog>
<Popover.Heading>Title</Popover.Heading>
<div>Content</div>
</Popover.Dialog>
</Popover.Content>
</Popover>Key Changes
1. Component Structure
v2: Separate components (Popover, PopoverTrigger, PopoverContent)
v3: Compound components (Popover, Popover.Trigger, Popover.Content, Popover.Dialog, Popover.Heading, Popover.Arrow)
2. Prop Changes
| v2 Prop | v3 Prop | Notes |
|---|---|---|
placement | placement (on Content) | Moved to Popover.Content |
showArrow | - | Removed (use Popover.Arrow component) |
size | - | Removed (use Tailwind CSS) |
color | - | Removed (use Tailwind CSS) |
radius | - | Removed (use Tailwind CSS) |
shadow | - | Removed (use Tailwind CSS) |
backdrop | - | Removed |
offset | offset (on Content) | Moved to Popover.Content |
shouldFlip | shouldFlip (on Content) | Moved to Popover.Content |
motionProps | - | Removed (animations handled differently) |
classNames | - | Use className props |
onClose | - | Use onOpenChange instead |
3. Removed Props
The following props are no longer available in v3:
size- Use Tailwind CSS classescolor- Use Tailwind CSS classesradius- Use Tailwind CSS classesshadow- Use Tailwind CSS classesbackdrop- RemovedshowArrow- UsePopover.Arrowcomponent insteadmotionProps- Animations handled differentlyclassNames- UseclassNameprops on individual componentsonClose- UseonOpenChangeinstead
Migration Examples
Basic Usage
import { Popover, PopoverTrigger, PopoverContent, Button } from "@heroui/react";
export default function App() {
return (
<Popover placement="right">
<PopoverTrigger>
<Button>Open Popover</Button>
</PopoverTrigger>
<PopoverContent>
<div className="px-1 py-2">
<div className="text-small font-bold">Popover Content</div>
<div className="text-tiny">This is the popover content</div>
</div>
</PopoverContent>
</Popover>
);
}import { Popover, Button } from "@heroui/react";
export default function App() {
return (
<Popover>
<Button>Open Popover</Button>
<Popover.Content placement="right">
<Popover.Dialog>
<Popover.Heading>Popover Content</Popover.Heading>
<p className="text-muted mt-2 text-sm">
This is the popover content
</p>
</Popover.Dialog>
</Popover.Content>
</Popover>
);
}With Arrow
<Popover showArrow>
<PopoverTrigger>
<Button>Open</Button>
</PopoverTrigger>
<PopoverContent>
<div>Content</div>
</PopoverContent>
</Popover><Popover>
<Button>Open</Button>
<Popover.Content>
<Popover.Dialog>
<Popover.Arrow />
<div>Content</div>
</Popover.Dialog>
</Popover.Content>
</Popover>With Placement
<Popover placement="top">
<PopoverTrigger>
<Button>Open</Button>
</PopoverTrigger>
<PopoverContent>
<div>Content</div>
</PopoverContent>
</Popover><Popover>
<Button>Open</Button>
<Popover.Content placement="top">
<Popover.Dialog>
<Popover.Arrow />
<div>Content</div>
</Popover.Dialog>
</Popover.Content>
</Popover>With Heading
<PopoverContent>
<div className="px-1 py-2">
<div className="text-small font-bold">Title</div>
<div className="text-tiny">Content</div>
</div>
</PopoverContent><Popover.Content>
<Popover.Dialog>
<Popover.Heading>Title</Popover.Heading>
<p className="text-muted mt-2 text-sm">Content</p>
</Popover.Dialog>
</Popover.Content>Controlled
import { useState } from "react";
const [isOpen, setIsOpen] = useState(false);
<Popover isOpen={isOpen} onOpenChange={setIsOpen}>
<PopoverTrigger>
<Button>Open</Button>
</PopoverTrigger>
<PopoverContent>
<div>Content</div>
</PopoverContent>
</Popover>import { useState } from "react";
const [isOpen, setIsOpen] = useState(false);
<Popover isOpen={isOpen} onOpenChange={setIsOpen}>
<Button>Open</Button>
<Popover.Content>
<Popover.Dialog>
<div>Content</div>
</Popover.Dialog>
</Popover.Content>
</Popover>With Offset
<Popover offset={10}>
<PopoverTrigger>
<Button>Open</Button>
</PopoverTrigger>
<PopoverContent>
<div>Content</div>
</PopoverContent>
</Popover><Popover>
<Button>Open</Button>
<Popover.Content offset={10}>
<Popover.Dialog>
<div>Content</div>
</Popover.Dialog>
</Popover.Content>
</Popover>Custom Trigger
<PopoverTrigger>
<CustomButton>Custom</CustomButton>
</PopoverTrigger><Popover.Trigger>
<CustomButton>Custom</CustomButton>
</Popover.Trigger>Custom Styling
<Popover
classNames={{
base: "custom-base",
content: "custom-content"
}}
>
<PopoverTrigger>
<Button>Open</Button>
</PopoverTrigger>
<PopoverContent>
<div>Content</div>
</PopoverContent>
</Popover><Popover>
<Button>Open</Button>
<Popover.Content className="custom-content">
<Popover.Dialog className="custom-dialog">
<div>Content</div>
</Popover.Dialog>
</Popover.Content>
</Popover>Component Anatomy
The v3 Popover follows this structure:
Popover (Root)
├── Popover.Trigger (optional, or use Button directly)
└── Popover.Content
└── Popover.Dialog
├── Popover.Arrow (optional)
├── Popover.Heading (optional)
└── ContentBreaking Changes Summary
- Component Structure: Must use compound components (
Popover.Content,Popover.Dialog, etc.) - Trigger: Can use
Popover.Triggeror Button directly - Content Wrapper: Content must be wrapped in
Popover.Dialog - Arrow:
showArrowprop removed - usePopover.Arrowcomponent - Heading: Use
Popover.Headingcomponent for titles - Props Moved:
placement,offset,shouldFlipmoved toPopover.Content - Styling Props Removed:
size,color,radius,shadow- use Tailwind CSS - Backdrop Removed:
backdropprop removed - Motion Removed:
motionPropsremoved, animations handled differently - ClassNames Removed: Use
classNameprops on individual components
Tips for Migration
- Update structure: Wrap content in
Popover.ContentandPopover.Dialog - Move placement: Move
placementprop toPopover.Content - Add arrow: Use
Popover.Arrowcomponent instead ofshowArrowprop - Add heading: Use
Popover.Headingfor titles - Update trigger: Use
Popover.Triggeror Button directly - Move offset: Move
offsetprop toPopover.Content - Update styling: Use Tailwind CSS classes for sizes, colors, radius, shadows
- Remove backdrop: Backdrop functionality removed
Need Help?
For v3 Popover features and API:
- See the API Reference
- Check interactive examples
For community support: