Popover

A popover component for displaying floating content relative to a trigger element

Installation

Terminal
pnpm add @choice-ui/popover

Import

Component.tsx
import { Popover, type PopoverProps } from "@choice-ui/popover"

Basic

`Popover` is a versatile floating overlay component for displaying contextual content.
Features:
- Multiple positioning options with automatic adjustment - Various interaction modes (click, hover, focus) - Optional draggable behavior - Controlled and uncontrolled usage - Header component for titles or complex UI - Support for nested interactive elements - Outside press handling with customizable ignore zones
Usage Guidelines:
- Use for contextual information, forms, or interactive controls - Choose appropriate interaction mode based on content importance - Consider placement based on available screen space - Add headers for context when content is complex - Use controlled mode when you need to manage open state externally
Accessibility:
- Proper focus management - Keyboard navigation support - Appropriate ARIA attributes - Screen reader announcements for state changes - Escape key dismissal Basic: Demonstrates the simplest Popover implementation.
Features:
- Click interaction (default behavior) - Automatic positioning - Clean, consistent styling
This example shows the minimal configuration required to implement a functional popover with a button trigger and text content.

Offset

Offset: Demonstrates customizing the distance between trigger and popover.
Features:
- Configurable spacing between trigger and content - Maintains proper positioning and alignment
This pattern is useful for:
- Creating more space between the trigger and content - Avoiding overlap with nearby elements - Achieving specific design requirements

Interactions

Interactions: Demonstrates different ways to trigger the popover.
Features:
- Click interaction (default) - Hover interaction with optimized configuration - Focus interaction for accessibility - Manual control with none interaction
Note: Hover interaction has been optimized to prevent flickering:
- move: false - prevents accidental triggers during movement - mouseOnly: true - avoids touch event interference - optimized delays and safePolygon settings

Click (Default)

Hover

Focus

Manual Control

Controlled

Controlled: Demonstrates managing the popover's open state externally.
Features:
- External state management - Programmatic open/close control - Visual feedback on the trigger button
This pattern is useful for:
- Complex interactions with other components - Form validation or data-dependent display - Wizard or stepped interfaces

Trigger Ref

TriggerRef: Demonstrates using an external trigger element.
Features:
- Reference to external trigger element - Complete separation of trigger and popover - Controlled open state
This pattern is useful for:
- Complex layouts where the trigger needs to be in a different component - Dynamically generated UI where the popover needs to be positioned relative to existing elements - Advanced application architectures with separated components

Trigger Selector

TriggerSelector: Demonstrates using a CSS selector to bind popover to an element.
Features:
- Supports any valid CSS selector (#id, .class, [data-*], etc.) - Same functionality as triggerRef - triggerRef takes priority if both are provided
This pattern is useful for:
- When you cannot access the element via ref (e.g., third-party components) - When the trigger element is rendered elsewhere in the DOM - When you prefer a simpler, selector-based approach

Using #id selector

Using .class selector

Using [data-*] selector

Trigger Selector With Dropdown

TriggerSelectorWithDropdown: Demonstrates using triggerSelector to position Popover relative to a Dropdown's parent container when triggered from a Dropdown item.
Features:
- Popover triggered from within a Dropdown menu item - Popover positioned relative to the parent container (not the menu item) - Useful for secondary actions that need more space
Use case:
- Click a Dropdown item to open a Popover with additional options or forms - The Popover appears anchored to a stable element rather than the ephemeral menu item

Click "Open Settings" in the Dropdown to open the Popover anchored to the container.

Placement

Placement: Demonstrates different positioning options for the popover.
Features:
- 12 different placement options - Automatically adjusts to available space - Dynamic positioning based on trigger location
Usage Guidelines:
- Choose appropriate placement based on UI layout - Consider screen edges and available space - Default to logical positions (e.g., dropdown menus below triggers)

Draggable

Draggable: Demonstrates a draggable popover with header.
Features:
- User can move the popover by dragging the header - Maintains state and content during dragging - Provides header as drag handle
This pattern is useful for:
- Complex UI where users may need to see content behind the popover - Workspaces or dashboard interfaces - Multi-step forms where comparing information is needed

Remember Position

RememberPosition: Demonstrates a popover that remembers its position when closed.
Features:
- Maintains its position when closed - Reappears in the same position when opened
This pattern is useful for:
- Popovers that need to remember their position when closed - Dashboard interfaces where popovers need to be in a specific location

Outside Press Ignore

OutsidePressIgnore: Demonstrates excluding elements from outside click dismissal.
Features:
- Define areas where clicks won't dismiss the popover - Maintains typical behavior for non-ignored areas - Uses CSS class-based targeting
This pattern is useful for:
- Complex interfaces with related but separate UI elements - Preventing accidental dismissal for important popovers - Creating modal-like experiences without full modals

Outside Press Ignore Array

OutsidePressIgnoreArray: Demonstrates excluding specific elements from outside click dismissal.
Features:
- Exclude specific elements from outside click dismissal - Maintains typical behavior for non-ignored areas - Uses array value to determine if specific elements should be ignored
This pattern is useful for:
- Complex interfaces with related but separate UI elements - Preventing accidental dismissal for important popovers - Creating modal-like experiences without full modals
Outside Press Ignore 1
Outside Press Ignore 2

Outside Press Ignore Boolean

OutsidePressIgnoreBoolean: Demonstrates excluding all elements from outside click dismissal.
Features:
- Exclude all elements from outside click dismissal - Maintains typical behavior for non-ignored areas - Uses boolean value to determine if all elements should be ignored
This pattern is useful for:
- Complex interfaces with related but separate UI elements - Preventing accidental dismissal for important popovers - Creating modal-like experiences without full modals

Nested

Nested: Demonstrates popovers containing other interactive components.
Features:
- Proper nesting of interactive components - Focus and event handling across nested elements - Multiple overlay layers with correct stacking
This pattern is useful for:
- Complex application interfaces - Rich editing tools or property panels - Form interfaces requiring nested selection controls

Auto Height

AutoHeight: Demonstrates a popover with auto height.
Features:
- Automatically adjusts the height of the popover content - Maintains typical behavior for non-ignored areas

Multi Trigger

Max Width

MaxWidth: Demonstrates the maxWidth prop functionality. By default, popovers will not have a maximum width. This story shows a popover with a maximum width of 640px.

Close On Escape

CloseOnEscape: Demonstrates the closeOnEscape prop functionality. By default, popovers can be closed with the ESC key. This story shows two popovers - one with ESC key enabled (default) and one with it disabled.

Press ESC to close

ESC key disabled

Match Trigger Width

MatchTriggerWidth: Demonstrates the matchTriggerWidth prop functionality. By default, popovers will not match the width of the trigger. This story shows two popovers - one with matchTriggerWidth enabled and one with it disabled.

With Input

WithInput: Demonstrates a popover containing input fields for user data entry. This example shows a typical form popover pattern with text inputs and action buttons.
Keyboard behavior:
- ESC in input field: Blur the input (does not close popover) - ESC outside input field: Close the popover
Implementation: Input handles ESC to blur and stops propagation. Popover only receives ESC events when focus is not on an input.

As Form

AsForm: Demonstrates using the `as` prop to render the popover container as a form element. This allows wrapping all popover content in a native HTML form for better form semantics.
Benefits:
- Native form validation - Submit on Enter key in inputs - Form data can be collected via FormData API - Better accessibility with proper form semantics
Usage: Set `as="form"` and add `onSubmit` handler to the Popover.

With Use Form

WithUseForm: Demonstrates integrating Popover with the `useForm` hook for complex form handling. This example shows how to use the `as="form"` prop combined with `useForm` for:
- Field-level validation with real-time feedback - Form state management - Structured form submission - Reset form on popover close
The `as="form"` prop allows the popover to act as a native form element, enabling proper form semantics while `useForm` provides powerful validation and state management.

API reference

DragPopoverTypeDefault
as
ElementType<any, keyof IntrinsicElements>
|
undefined
-
autoSize
boolean
|
undefined
-
autoUpdate
boolean
|
undefined
-
className
string
|
undefined
-
closeOnEscape
boolean
|
undefined
-
contentRef
RefObject<HTMLDivElement>
|
undefined
-
defaultOpen
boolean
|
undefined
-
delay
{ close?: number
|
undefined; open?: number
|
undefined; }
|
undefined
-
draggable
boolean
|
undefined
-
focusManagerProps
Partial<FloatingFocusManagerProps>
|
undefined
-
interactions
undefined
|
"hover"
|
"click"
|
"focus"
|
"none"
-
matchTriggerWidth
boolean
|
undefined
-
maxWidth
number
|
undefined
-
offset
OffsetOptions
|
undefined
-
onOpenChange
((isOpen: boolean) => void)
|
undefined
-
open
boolean
|
undefined
-
outsidePressIgnore
string
|
boolean
|
string[]
|
undefined
-
placement
undefined
|
"top"
|
"right"
|
"bottom"
|
"left"
|
"top-start"
|
"top-end"
|
"right-start"
|
"right-end"
|
"bottom-start"
|
"bottom-end"
|
"left-start"
|
"left-end"
-
portalId
string
|
undefined
-
rememberPosition
boolean
|
undefined
-
root
HTMLElement
|
null
|
undefined
-
triggerRef
RefObject<HTMLElement>
|
undefined
-
triggerSelector
string
|
undefined
-
PopoverPropsTypeDefault
as
ElementType<any, keyof IntrinsicElements>
|
undefined
-
autoSize
boolean
|
undefined
-
autoUpdate
boolean
|
undefined
-
className
string
|
undefined
-
closeOnEscape
boolean
|
undefined
-
contentRef
RefObject<HTMLDivElement>
|
undefined
-
defaultOpen
boolean
|
undefined
-
delay
{ close?: number
|
undefined; open?: number
|
undefined; }
|
undefined
-
draggable
boolean
|
undefined
-
focusManagerProps
Partial<FloatingFocusManagerProps>
|
undefined
-
interactions
undefined
|
"hover"
|
"click"
|
"focus"
|
"none"
-
matchTriggerWidth
boolean
|
undefined
-
maxWidth
number
|
undefined
-
offset
OffsetOptions
|
undefined
-
onOpenChange
((isOpen: boolean) => void)
|
undefined
-
open
boolean
|
undefined
-
outsidePressIgnore
string
|
boolean
|
string[]
|
undefined
-
placement
undefined
|
"top"
|
"right"
|
"bottom"
|
"left"
|
"top-start"
|
"top-end"
|
"right-start"
|
"right-end"
|
"bottom-start"
|
"bottom-end"
|
"left-start"
|
"left-end"
-
portalId
string
|
undefined
-
rememberPosition
boolean
|
undefined
-
root
HTMLElement
|
null
|
undefined
-
triggerRef
RefObject<HTMLElement>
|
undefined
-
triggerSelector
string
|
undefined
-