remix/ui/popover
popover is a low-level primitive for anchored, dismissible floating panels.
Use it for custom surfaces like filters, inspectors, and view options. Higher-level widgets like menu, select, and combobox should build on top of it instead of exposing raw popover.* mixins directly.
Usage
import { css, on, type Handle } from 'remix/ui'
import { Button } from 'remix/ui/button'
import { Glyph } from 'remix/ui/glyph'
import { popover } from 'remix/ui/popover'
export function ViewOptions(handle: Handle) {
let open = false
function openPopover() {
open = true
void handle.update()
}
function closePopover() {
open = false
void handle.update()
}
return () => (
<popover.Context>
<Button
endIcon={<Glyph name="chevronDown" />}
mix={[
popover.anchor({ placement: 'bottom-end' }),
popover.focusOnHide(),
on('click', openPopover),
]}
tone="secondary"
>
View options
</Button>
<div
mix={[
popover.surfaceStyle,
popover.surface({
open,
onHide() {
closePopover()
},
}),
]}
>
<div mix={popover.contentStyle}>
<Button mix={[popover.focusOnShow(), on('click', closePopover)]} tone="ghost">
Close
</Button>
<div mix={panelBody}>Panel content</div>
</div>
</div>
</popover.Context>
)
}
let panelBody = css({
padding: '12px',
})popover.*
popover.Context
Provides shared coordination for one popover instance. Render the anchor, any focus targets, and the surface inside the same context.
popover.anchor(options)
Registers the host element as the anchor for the current popover surface.
- Accepts standard
AnchorOptions. - The stored anchor controls where the surface is positioned when it opens.
- Apply it to the button or other element the surface should attach to.
popover.surface({ open, onHide, ... })
Turns the host into the controlled popover surface.
- Wires
popover="manual"and nativeshowPopover()/hidePopover()behavior. - Calls
onHideforEscapeand outside clicks with aPopoverHideRequest. - Restores focus to the registered hide target unless
restoreFocusOnHide: false. - Accepts
closeOnAnchorClick: falsewhen the anchor must stay interactive while open.
Apply this to the actual floating root, not a nested child.
popover.focusOnShow()
Registers the element that should receive focus when the popover opens.
popover.focusOnHide()
Registers the element that should receive focus again when the popover closes.
popover.surfaceStyle
Default floating-surface presentation for popovers.
popover.contentStyle
Default inner scroll container for popover content.
Behavior Notes
- Opening anchors the surface to the registered anchor and locks page scrolling until close.
onHidereceives{ reason: 'escape-key' | 'outside-click', target? }.popover.focusOnShow()wins on open when present.popover.focusOnHide()is used on close by default when focus restoration is enabled.closeOnAnchorClick: falsekeeps anchor clicks inside the current session, which is useful for input-driven popovers like comboboxes.
When To Use Something Else
- Use
menufor command surfaces. - Use
listboxorselectfor committed value picking. - Use
comboboxfor input-first popup selection.