Raft 设计系统

组件 · 浮层

Popover

A small panel that opens next to the element people click, for a little input such as a choice, a field and a button.

稳定
import { Popover } from "@botiverse/raft-ui";
本页尚未翻译
译文完成之前,这里显示英文原文。 阅读英文版

A popover is a small panel that opens next to the element people click and holds a little input: a choice of a few options, a field, a button. Snoozing a notification or renaming something fits in one. It closes on a click outside or Esc.

When to use

SituationUse
One sentence about something, on hoverTooltip
A summary of a person or an agent, on hover, with linksPreviewCard
A little choice or input, on click (snooze, rename)Popover, with a RadioGroup, an Input and buttons
A list of actionsDropdownMenu
Something that stays open and scrollsDrawer

Which overlay fits which job is in Choosing a component.

Anatomy

  • Popover: the root. Owns the open state. Required.
  • PopoverTrigger: the element that opens it. Required.
  • PopoverContent: the panel, portaled and positioned next to the trigger. Required.
  • PopoverHeader: a row with PopoverTitle and an optional PopoverClose.
  • PopoverTitle and PopoverDescription: the title and a sentence under it.
  • PopoverSeparator: a hairline between parts of the panel.
  • PopoverClose: a button that closes the popover.
  • PopoverArrow: an optional pointer toward the trigger.
  • PopoverBackdrop: a transparent layer behind the panel that catches clicks outside it.
  • PopoverPortal, PopoverViewport and PopoverPopup: lower-level parts. PopoverPopup is the panel surface without positioning.

Behavior

  • The popover opens below its trigger, aligned to its start edge, and moves or flips when it meets the window edge (Elevation).
  • A click outside and Esc close it. A Cancel button closes it too.
  • It has no scrim; the page behind it stays as it is.

Content

  • Write button labels in Title Case, with the confirm button repeating the verb: Snooze, Rename (Writing).

Accessibility

  • Popover wraps the Base UI Popover. It provides the dialog role on the panel, moves focus into it on open, and returns focus to the trigger on Esc.
  • Name the panel: PopoverTitle labels it. Without a visible title, put an aria-label on PopoverContent.
  • Give an icon-only trigger an aria-label.

Rules

  • Make a popover 300px wide, with 16px padding.
  • Don't put a pink button in a popover. Confirm with an ink-border button (variant="outline") and cancel with variant="ghost": a popover is a small step, not the screen's primary action.

API

Popover

Prop类型默认值
actionsRefA ref to imperative actions. - `unmount`: Manually unmounts the popover. Call this after any externally controlled closing animation finishes. - `close`: Closes the popover imperatively when called.RefObject<PopoverRootActions | null>
childrenThe content of the popover. This can be a regular React node or a render function that receives the `payload` of the active trigger.ReactNode | PayloadChildRenderFunction<unknown>
defaultOpenWhether the popover is initially open.booleanfalse
defaultTriggerIdID of the trigger that the popover is associated with. This is useful in conjunction with the `defaultOpen` prop to create an initially open popover.string
handleA handle to associate the popover with a trigger. If specified, allows external triggers to control the popover's open state.BasePopover.Handle<unknown>
modalDetermines if the popover enters a modal state when open. - `true`: user interaction is limited to the popover: document page scroll is locked, and pointer interactions on outside elements are disabled. - `false`: user interaction with the rest of the document is allowed. - `'trap-focus'`: focus is trapped inside the popover, but document page scroll is not locked and pointer interactions outside of it remain enabled.boolean | "trap-focus"false
onOpenChangeEvent handler called when the popover is opened or closed.(open: boolean, eventDetails: BasePopover.Root.ChangeEventDetails) => void
onOpenChangeCompleteEvent handler called after any animations complete when the popover is opened or closed.(open: boolean) => void
openWhether the popover is currently open.boolean
triggerIdID of the trigger that the popover is associated with. This is useful in conjunction with the `open` prop to create a controlled popover. There's no need to specify this prop when the popover is uncontrolled (that is, when the `open` prop is not set).string

PopoverArrow, PopoverBackdrop

Prop类型默认值
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

PopoverClose

Prop类型默认值
nativeButtonWhether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`).booleantrue
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

PopoverContent

Prop类型默认值
containerHTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null>
portalPropsPopoverPortalProps
alignHow to align the popup relative to the specified side.Align"start"
alignOffsetAdditional offset along the alignment axis in pixels. Also accepts a function that returns the offset to read the dimensions of the anchor and positioner elements, along with its side and alignment.number | OffsetFunction0
anchorAn element to position the popup against. By default, the popup will be positioned against the trigger.Element | VirtualElement | RefObject<Element | null> | (() => Element | VirtualElement | null)
arrowPaddingMinimum distance to maintain between the arrow and the edges of the popup.number5
collisionAvoidanceDetermines how to handle collisions when positioning the popup.CollisionAvoidance
collisionBoundaryAn element or a rectangle that delimits the area that the popup is confined to.Boundary'clipping-ancestors'
collisionPaddingAdditional space to maintain from the edge of the collision boundary.Padding5
disableAnchorTrackingWhether to disable the popup from tracking any layout shift of its positioning anchor.booleanfalse
finalFocusDetermines the element to focus when the popover is closed.boolean | RefObject<HTMLElement | null> | ((closeType: InteractionType) => void | boolean | HTMLElement | null)
initialFocusDetermines the element to focus when the popover is opened. By default, focus moves to the first tabbable element inside the popup, except when the popover is opened by touch — then the popup itself is focused to avoid opening the virtual keyboard.boolean | RefObject<HTMLElement | null> | ((openType: InteractionType) => void | boolean | HTMLElement | null)
positionMethodDetermines which CSS `position` property to use."fixed" | "absolute""fixed"
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)
sideWhich side of the anchor element to align the popup against. May automatically change to avoid collisions.Side"bottom"
sideOffsetDistance between the anchor and the popup in pixels. Also accepts a function that returns the distance to read the dimensions of the anchor and positioner elements, along with its side and alignment.number | OffsetFunction4
stickyWhether to maintain the popup in the viewport after the anchor element was scrolled out of view.booleanfalse

Also takes the attributes of its element.

PopoverDescription

Prop类型默认值
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

PopoverHeader, PopoverPopup

接受其元素的全部属性。

PopoverPortal

Prop类型默认值
containerA parent element to render the portal element into.HTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null>
keepMountedWhether to keep the portal mounted in the DOM while the popup is hidden.booleanfalse
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

PopoverSeparator

接受其元素的全部属性。

PopoverTitle

Prop类型默认值
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

PopoverTrigger

Prop类型默认值
closeDelayHow long to wait before closing the popover that was opened on hover. Specified in milliseconds.number0
delayHow long to wait before the popover may be opened on hover. Specified in milliseconds.number300
handleA handle to associate the trigger with a popover.BasePopover.Handle<unknown>
nativeButtonWhether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`). Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (e.g. `<div>`).booleantrue
openOnHoverWhether the popover should also open when the trigger is hovered.booleanfalse
payloadA payload to pass to the popover when it is opened.{}
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

PopoverViewport

Prop类型默认值
childrenThe content to render inside the transition container.ReactNode
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.