Preview Only: These components are for reference only. Continue using Orbiter in production until further notice.

Popover

A popover displays additional content when a user interacts with a trigger element.

import { Button, Content, Footer, Heading, Link, Popover, PopoverTrigger } from "@hopper-ui/components"; export default function Example() { return ( <PopoverTrigger> <Button aria-label="information" variant="secondary">Company Profile</Button> <Popover> <Heading>ACME</Heading> <Content> A tech company focusing on the development of software and hardware solutions. </Content> <Footer> <Link href="#">Website</Link> </Footer> </Popover> </PopoverTrigger> ); }

Anatomy

Composed Components

A Popover uses the following components:

Usage

Disabled

A popover will not open when its trigger is disabled.

import { Button, Content, Heading, Popover, PopoverTrigger } from "@hopper-ui/components"; export default function Example() { return ( <PopoverTrigger> <Button isDisabled>Company Profile</Button> <Popover> <Heading>ACME</Heading> <Content> A tech company focusing on the development of software and hardware solutions. </Content> </Popover> </PopoverTrigger> ); }

Single button

A popover can have a single button.

import { Button, Content, Heading, Popover, PopoverTrigger } from "@hopper-ui/components"; export default function Example() { return ( <PopoverTrigger> <Button variant="secondary">Company Profile</Button> <Popover> <Heading>ACME</Heading> <Content> A tech company focusing on the development of software and hardware solutions. </Content> <Button>Apply</Button> </Popover> </PopoverTrigger> ); }

Multiple buttons

A popover can have a group of buttons.

import { Button, ButtonGroup, Content, Heading, Popover, PopoverTrigger } from "@hopper-ui/components"; export default function Example() { return ( <PopoverTrigger> <Button>Company Profile</Button> <Popover> <Heading>ACME</Heading> <Content> A tech company focusing on the development of software and hardware solutions. </Content> <ButtonGroup> <Button variant="secondary">Follow</Button> <Button>Apply</Button> </ButtonGroup> </Popover> </PopoverTrigger> ); }

A popover can have footer text.

import { Button, Content, Footer, Heading, Popover, PopoverTrigger } from "@hopper-ui/components"; export default function Example() { return ( <PopoverTrigger> <Button variant="secondary">Company Profile</Button> <Popover> <Heading>ACME</Heading> <Content> A tech company focusing on the development of software and hardware solutions. </Content> <Footer> 1 of 5 </Footer> <Button>Next</Button> </Popover> </PopoverTrigger> ); }

Placement

A popover can be positioned in different ways top, right, bottom, left.

import { Button, PopoverTrigger, Popover, Heading, Content, Inline } from "@hopper-ui/components"; export default function Example() { return ( <Inline> <PopoverTrigger> <Button aria-label="top popover" variant="secondary">Top</Button> <Popover placement="top"> <Heading>Popover top</Heading> <Content> And here's some amazing content. It's very engaging. Right? </Content> </Popover> </PopoverTrigger> <PopoverTrigger> <Button aria-label="right popover" variant="secondary">Right</Button> <Popover placement="right"> <Heading>Popover right</Heading> <Content> And here's some amazing content. It's very engaging. Right? </Content> </Popover> </PopoverTrigger> <PopoverTrigger> <Button aria-label="bottom popover" variant="secondary">Bottom</Button> <Popover placement="bottom"> <Heading>Popover bottom</Heading> <Content> And here's some amazing content. It's very engaging. Right? </Content> </Popover> </PopoverTrigger> <PopoverTrigger> <Button aria-label="left popover" variant="secondary">Left</Button> <Popover placement="left"> <Heading>Popover left</Heading> <Content> And here's some amazing content. It's very engaging. Right? </Content> </Popover> </PopoverTrigger> </Inline> ); }

Context

A Popover's isOpen state or close function can be retrieved from PopoverContext and ButtonContext.

import { Button, ButtonContext, Content, Heading, Popover, PopoverContext, PopoverTrigger, SlotProvider } from "@hopper-ui/components"; import { type ReactNode, useRef, useState } from "react"; const HighlightedTrigger = ({ children }: { children: ReactNode }) => { const triggerRef = useRef(null); const [isOpen, setOpen] = useState(false); return ( <SlotProvider values={[ [PopoverContext, { isOpen, onOpenChange: setOpen }], [ButtonContext, { onPress: () => setOpen(!isOpen), ref: triggerRef, variant: isOpen ? "primary" : "secondary" }] ]} > {children} </SlotProvider> ); }; export default function Example() { return ( <HighlightedTrigger> <PopoverTrigger> <Button>Company Profile</Button> <Popover> <Heading>ACME</Heading> <Content> A tech company focusing on the development of software and hardware solutions. </Content> </Popover> </PopoverTrigger> </HighlightedTrigger> ); }

Controlled

A Popover's open state can be handled in controlled mode.

import { Button, Content, Heading, Popover, Stack } from "@hopper-ui/components"; import { useRef, useState } from "react"; export default function Example() { const triggerRef = useRef(null); const [isOpen, setOpen] = useState(false); return ( <> <Stack alignX="center"> <Button onPress={() => setOpen(!isOpen)} variant="secondary" > Company Profile </Button> <span ref={triggerRef}>Popover will be positioned relative to me</span> </Stack> <Popover triggerRef={triggerRef} isOpen={isOpen} onOpenChange={setOpen}> <Heading>ACME</Heading> <Content> A tech company focusing on the development of software and hardware solutions. </Content> </Popover> </> ); }

Styled React Aria Component Popover

If you want to create a custom component using a Popover, and you just need the Popover styles, you can use the PopoverBase component instead.

Props

Popover

isAutoWidth?
boolean

Whether the popover should have an auto width. Only available in non-dialog popovers.

boundaryOffset?
number

The minimum distance the trigger edge should be from the edge of the overlay element.

isNonDialog?
boolean

Whether the popover is a non-dialog. This is set to true in components such as selects.

containerProps?
PopoverContainerProps

The props of the popover's inner container.

placement?
ResponsiveProp<Placement>

The placement of the popover with respect to its anchor element.

Defaults to bottom.
style?
CSSProperties | ((values: PopoverRenderProps & { defaultStyle: CSSProperties; }) => CSSProperties)

The inline style for the element. A function may be provided to compute the style based on component state.

isOpen?
boolean

Whether the overlay is open by default (controlled).

containerPadding?
number

The placement padding that should be applied between the element and its surrounding container.

Defaults to 12.
offset?
number

The additional offset applied along the main axis between the element and its anchor element.

Defaults to 8.
crossOffset?
number

The additional offset applied along the cross axis between the element and its anchor element.

Defaults to 0.
shouldFlip?
boolean

Whether the element should flip its orientation (e.g. top to bottom or left to right) when there is insufficient room for it to render completely.

Defaults to true.
triggerRef?
RefObject<Element | null>

The ref for the element which the popover positions itself with respect to.

When used within a trigger component such as DialogTrigger, MenuTrigger, Select, etc., this is set automatically. It is only required when used standalone.

boundaryElement?
Element

Element that that serves as the positioning boundary.

Defaults to document.body.
scrollRef?
RefObject<Element | null>

A ref for the scrollable region within the overlay.

Defaults to overlayRef.
shouldUpdatePosition?
boolean

Whether the overlay should update its position automatically.

Defaults to true.
arrowBoundaryOffset?
number

The minimum distance the arrow's edge should be from the edge of the overlay element.

Defaults to 0.
isNonModal?
boolean

Whether the popover is non-modal, i.e. elements outside the popover may be interacted with by assistive technologies.

Most popovers should not use this option as it may negatively impact the screen reader experience. Only use with components such as combobox, which are designed to handle this situation carefully.

isKeyboardDismissDisabled?
boolean

Whether pressing the escape key to close the popover should be disabled.

Most popovers should not use this option. When set to true, an alternative way to close the popover with a keyboard must be provided.

Defaults to false.
shouldCloseOnInteractOutside?
((element: Element) => boolean)

When user interacts with the argument element outside of the popover ref, return true if onClose should be called. This gives you a chance to filter out interaction with elements that should not dismiss the popover. By default, onClose will always be called on interaction outside the popover ref.

trigger?
string

The name of the component that triggered the popover. This is reflected on the element as the data-trigger attribute, and can be used to provide specific styles for the popover depending on which element triggered it.

isEntering?
boolean

Whether the popover is currently performing an entry animation.

isExiting?
boolean

Whether the popover is currently performing an exit animation.

UNSTABLE_portalContainer?
Element

The container element in which the overlay portal will be placed. This may have unknown behavior depending on where it is portalled to.

Defaults to document.body.
defaultOpen?
boolean

Whether the overlay is open by default (uncontrolled).

children?
ReactNode | ((values: PopoverRenderProps & { defaultChildren: ReactNode; }) => ReactNode)

The children of the component. A function may be provided to alter the children based on component state.

className?
string | ((values: PopoverRenderProps & { defaultClassName: string; }) => string)

The CSS className for the element. A function may be provided to compute the class based on component state.

PopoverTrigger

isOpen?
boolean

Whether the overlay is open by default (controlled).

defaultOpen?
boolean

Whether the overlay is open by default (uncontrolled).

Migration Notes

Coming from Orbiter, you should be aware of the following changes:

  • The position property has been renamed placement.