- Published on
How to Close Radix/Shadcn Popover from Inside
- Authors
- Name
- Ripal & Zalak
Introduction
Radix and Shadcn provide flexible UI primitives, including the Popover
component, which is highly customizable. However, developers often face challenges when trying to close a Popover
programmatically from inside its content. This guide explains multiple approaches to achieve this.
The Problem
The Popover
component doesn’t provide a direct built-in method to close itself programmatically from inside its content. A typical use case is having buttons inside the PopoverContent
that trigger specific actions and close the Popover
afterward. Without proper handling, the Popover
remains open.
Solutions
1. Using Controlled State
Manage the Popover
's open state manually using the open
and onOpenChange
props. This approach ensures full control over when the Popover
opens and closes.
Example:
import { useState } from 'react'
import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover'
export function ControlledPopover() {
const [isOpen, setIsOpen] = useState(false)
const handleButtonClick = () => {
// Perform your action here
console.log('Button clicked!')
setIsOpen(false) // Close the popover
}
return (
<Popover open={isOpen} onOpenChange={setIsOpen}>
<PopoverTrigger asChild>
<button>Open Popover</button>
</PopoverTrigger>
<PopoverContent>
<button onClick={handleButtonClick}>Close Popover</button>
</PopoverContent>
</Popover>
)
}
PopoverClose
2. Using Radix UI provides a PopoverClose
component, which allows you to close the Popover
when interacting with an element inside it. This is a simple and declarative solution.
Example:
import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover'
import { PopoverClose } from '@radix-ui/react-popover'
export function DeclarativePopover() {
return (
<Popover>
<PopoverTrigger asChild>
<button>Open Popover</button>
</PopoverTrigger>
<PopoverContent>
<PopoverClose asChild>
<button>Close Popover</button>
</PopoverClose>
</PopoverContent>
</Popover>
)
}
onOpenChange
3. Combining Actions with You can handle the closing of the Popover
in combination with custom actions by listening to the onOpenChange
event.
Example:
import { useState } from 'react'
import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover'
export function PopoverWithCustomActions() {
const [isOpen, setIsOpen] = useState(false)
const handleSubmit = () => {
console.log('Action executed')
setIsOpen(false) // Close the popover
}
return (
<Popover open={isOpen} onOpenChange={setIsOpen}>
<PopoverTrigger asChild>
<button>Open Popover</button>
</PopoverTrigger>
<PopoverContent>
<form
onSubmit={(e) => {
e.preventDefault()
handleSubmit()
}}
>
<button type="submit">Submit & Close</button>
</form>
</PopoverContent>
</Popover>
)
}
Best Practices
- Controlled State: Use controlled components when you need precise control over the
Popover
's behavior. - Declarative Approach: Utilize
PopoverClose
for simpler use cases where you don’t need additional logic. - Accessibility: Ensure all actions are accessible and provide clear feedback to the user.
FAQs
1. Can I use PopoverClose
and controlled state together? Yes, but it’s usually unnecessary since controlled state gives you complete control over the Popover
.
2. Why doesn’t my Popover
close when clicking outside? Ensure you’re using onOpenChange
to manage the Popover
state. Radix UI automatically handles outside clicks if state is properly managed.
3. Is it possible to animate the Popover
closing? Yes, Radix UI supports animations via the asChild
prop and CSS transitions. You can wrap the PopoverContent
with a custom animated component.
Conclusion
Closing a Shadcn or Radix Popover
from inside its content is straightforward when using controlled state or the PopoverClose
component. Choose the approach that best suits your use case, and always ensure a smooth and accessible user experience.