import { Popover } from '@cerberus/react';The Popover component is a controlled abstraction of the primitive parts that can be used to show or hide content.
For advanced layouts, you can utilize the helper slots to streamline styling. Layout related slots correspond to the size variant provided.
The following slots are available on the Popover object:
| Component | Description |
|---|---|
Header | Useful for controlling header block styles. |
Body | Useful for controlling "body" block styles. |
Footer | Useful for controlling footer block styles. |
Title | Useful for controlling heading-related styles. |
Description | Useful for controlling body-related styles. |
The Popover component supports sizes: xs to lg. This changes the padding of the layout slots.
Set the usage prop to arrow to show an arrow tip.
Use the positioning.placement prop to configure the underlying floating-ui positioning logic.
Use the lazyMounted and/or unmountOnExit prop to defer the mounting of the popover content until it's opened.
Popovers can be nested within each other. Each nested popover maintains its own open state and positioning.
Use PopoverParts.Anchor to position the popover relative to a different element than the trigger.
You can customize the Popover using style props and data selectors on any slot primitve.
The following css variables are exposed to the PopoverPositioner which you can use to style the PopoverContent
// width of the popover trigger
--reference-width: <pixel-value>;
// width of the available viewport
--available-width: <pixel-value>;
// height of the available viewpor
--available-height: <pixel-value>;For example, if you want to make sure the maximum height doesn't exceed the available height, use the following css:
<Popover
css={{
'& :is([data-part=content])': {
maxHeight: calc(var(--available-height) - 100px);
}
}}
/>The layers of the Popover which can be used to create a fully custom solution.
| Component | Description |
|---|---|
| PopoverRoot | The main container for the popover. |
| PopoverTrigger | The trigger that toggles the popover content. |
| PopoverAnchor | The container to anchor the popover content to. |
| PopoverPositioner | The positioning container for the popover content. |
| PopoverArrow | The arrow container. |
| PopoverArrowTip | The actual visible arrow. |
| PopoverContent | The content container. |
| PopoverTitle | The heading for a popover. |
| PopoverDescription | The description for a popover. |
| PopoverCloseTrigger | The close trigger for a popover. |
| PopoverHeader | The header for a popover. |
| PopoverBody | The body for a popover. |
| PopoverFooter | The footer for a popover. |
The primitives additionally use the following data attributes for custom styling:
| Name | Value | Description |
|---|---|---|
data-scope | popover | The scope of the components. |
data-part | root | The root layer of the scope. |
data-part | trigger | The trigger layer of the scope. |
data-part | anchor | The anchor layer of the scope. |
data-part | anchor-tip | The anchor-tip layer of the scope. |
data-part | positioner | The positioner layer of the scope. |
data-part | arrow | The arrow layer of the scope. |
data-part | arrow-tip | The arrow-tip layer of the scope. |
data-part | content | The content layer of the scope. |
data-part | title | The title layer of the scope. |
data-part | description | The description layer of the scope. |
data-part | header | The header layer of the scope. |
data-part | body | The body layer of the scope. |
data-part | footer | The footer layer of the scope. |
| Prop | Type | Required | Description |
|---|---|---|---|
autoFocus | boolean | No | Whether to automatically set focus on the first focusable content within the popover when opened. |
closeOnEscape | boolean | No | Whether to close the popover when the escape key is pressed. |
closeOnInteractOutside | boolean | No | Whether to close the popover when the user clicks outside of the popover. |
defaultOpen | boolean | No | The initial open state of the popover when rendered. Use when you don't need to control the open state of the popover. |
id | string | No | The unique identifier of the machine. |
ids | Partial<PrimitiveSlots> | No | The ids of the elements in the popover. Useful for composition. |
immediate | boolean | No | Whether to synchronize the present change immediately or defer it to the next frame |
initialFocusEl | () => HTMLElement | null | No | The element to focus on when the popover is opened. |
lazyMount | boolean | No | Whether to enable lazy mounting |
modal | boolean | No | Whether the popover should be modal. When set totrue: interaction with outside elements will be disabled, only popover content will be visible to screen readers, scrolling is blocked, focus is trapped within the popover |
onEscapeKeyDown | (event: KeyboardEvent) => void | No | Function called when the escape key is pressed |
onExitComplete | VoidFunction | No | Function called when the animation ends in the closed state |
onFocusOutside | (event: FocusOutsideEvent) => void | No | Function called when the focus is moved outside the component |
onInteractOutside | (event: InteractOutsideEvent) => void | No | Function called when an interaction happens outside the component |
onOpenChange | (details: OpenChangeDetails) => void | No | Function invoked when the popover opens or closes |
onPointerDownOutside | (event: PointerDownOutsideEvent) => void | No | Function called when the pointer is pressed down outside the component |
onRequestDismiss | (event: LayerDismissEvent) => void | No | Function called when this layer is closed due to a parent layer being closed |
open | boolean | No | The controlled open state of the popover |
persistentElements | (() => Element | null)[] | No | Returns the persistent elements that: should not have pointer-events disabled, should not trigger the dismiss event |
portalled | boolean | No | Whether the popover is portalled. This will proxy the tabbing behavior regardless of the DOM position of the popover content. |
positioning | PositioningOptions | No | The user provided options used to position the popover content |
present | boolean | No | Whether the node is present (controlled by the user) |
skipAnimationOnMount | boolean | No | Whether to allow the initial presence animation. |
unmountOnExit | boolean | No | Whether to unmount on exit. |
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| Variable | Description |
|---|---|
--arrow-size | The size of the arrow |
--arrow-size-half | Half the size of the arrow |
--arrow-background | Use this variable to style the arrow background |
--arrow-offset | The offset position of the arrow |
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| Attribute | Value |
|---|---|
[data-scope] | popover |
[data-part] | content |
[data-state] | "open" | "closed" |
[data-nested] | popover |
[data-has-nested] | popover |
[data-expanded] | Present when expanded |
[data-placement] | The placement of the content |
| Variable | Description |
|---|---|
--layer-index | The index of the dismissable in the layer stack |
--nested-layer-count | The number of nested popovers |
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| Attribute | Value |
|---|---|
[data-scope] | popover |
[data-part] | indicator |
[data-state] | "open" | "closed" |
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| Variable | Description |
|---|---|
--reference-width | The width of the reference element |
--reference-height | The height of the root |
--available-width | The available width in viewport |
--available-height | The available height in viewport |
--x | The x position for transform |
--y | The y position for transform |
--z-index | The z-index value |
--transform-origin | The transform origin for animations |
| Prop | Type | Required | Description |
|---|---|---|---|
value | UsePopoverReturn | Yes | |
immediate | boolean | No | Whether to synchronize the present change immediately or defer it to the next frame |
lazyMount | boolean | No | Whether to enable lazy mounting |
onExitComplete | VoidFunction | No | Function called when the animation ends in the closed state |
present | boolean | No | Whether the node is present (controlled by the user) |
skipAnimationOnMount | boolean | No | Whether to allow the initial presence animation. |
unmountOnExit | boolean | No | Whether to unmount on exit. |
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| Attribute | Value |
|---|---|
[data-scope] | popover |
[data-part] | trigger |
[data-placement] | The placement of the trigger |
[data-state] | "open" | "closed" |
On this page
'use client'
import { HStack } from '@/styled-system/jsx'
import { Button, Popover } from '@cerberus/react'
export function BasicDemo() {
return (
<Popover trigger={<Button>Trigger</Button>}>
<HStack p="md" w="full">
Everything is content...
</HStack>
</Popover>
)
}
'use client'
import { Button, Popover } from '@cerberus/react'
export function PlacementDemo() {
return (
<Popover
trigger={<Button>Trigger</Button>}
positioning={{
placement: 'left-start',
offset: { mainAxis: 12, crossAxis: 12 },
}}
>
<Popover.Body>Everything is content...</Popover.Body>
</Popover>
)
}
'use client'
import { Button, Popover } from '@cerberus/react'
export function LazyDemo() {
return (
<Popover trigger={<Button>Trigger</Button>} lazyMounted unmountOnExit>
<Popover.Body>Everything is content...</Popover.Body>
</Popover>
)
}
'use client'
import { Button, Popover } from '@cerberus/react'
export function NestedDemo() {
return (
<Popover trigger={<Button>Trigger</Button>}>
<Popover.Body>
This is the parent popover content.
<Popover
trigger={
<Button usage="outlined-subtle" size="sm">
Trigger
</Button>
}
>
<Popover.Body>This is the nested popover content.</Popover.Body>
</Popover>
</Popover.Body>
</Popover>
)
}
'use client'
import { HStack } from '@/styled-system/jsx'
import { Button, Input, PopoverParts } from '@cerberus/react'
export function AnchorDemo() {
return (
<PopoverParts.Root size="lg">
<HStack gap="md">
<PopoverParts.Trigger asChild>
<Button size="sm" usage="outlined-subtle">
Trigger
</Button>
</PopoverParts.Trigger>
<PopoverParts.Anchor>
<Input placeholder="Anchor..." size="sm" />
</PopoverParts.Anchor>
</HStack>
<PopoverParts.Positioner>
<PopoverParts.Content>
<PopoverParts.Body>This is anchored to the input.</PopoverParts.Body>
</PopoverParts.Content>
</PopoverParts.Positioner>
</PopoverParts.Root>
)
}
'use client'
import { PopoverParts } from '@cerberus/react'
export function CustomDemo() {
return (
<PopoverParts.Root size="lg">
<PopoverParts.Trigger>Custom Trigger</PopoverParts.Trigger>
<PopoverParts.Positioner>
<PopoverParts.Content bgColor="page.bg.100" border="2px solid" rounded="none">
<PopoverParts.Header pb="lg">This is a custom popover</PopoverParts.Header>
<PopoverParts.Body bgColor="page.bg.200">
That is fully built from scratch
</PopoverParts.Body>
<PopoverParts.Footer textStyle="heading-2xs">
Footer sturf
</PopoverParts.Footer>
</PopoverParts.Content>
</PopoverParts.Positioner>
</PopoverParts.Root>
)
}
'use client'
import { HStack } from '@/styled-system/jsx'
import { Button, Popover } from '@cerberus/react'
export function ArrowDemo() {
return (
<Popover trigger={<Button>Trigger</Button>} usage="arrow">
<HStack p="md" w="full">
Everything is content...
</HStack>
</Popover>
)
}
'use client'
import { HStack } from '@/styled-system/jsx'
import { Button, For, Popover } from '@cerberus/react'
export function SizesDemo() {
return (
<HStack gap="md">
<For each={['xs', 'sm', 'md', 'lg']}>
{(size: string) => (
<Popover key={size} trigger={<Button size="sm">{size}</Button>} size={size}>
<Popover.Body>This is a {size} popover</Popover.Body>
</Popover>
)}
</For>
</HStack>
)
}
'use client'
import { Box, Circle, Divider, Float, HStack, Stack } from '@/styled-system/jsx'
import { AiAgentInvocation, Chat, Time, UserFollow } from '@carbon/icons-react'
import { Avatar, Button, ButtonGroup, Popover, Text } from '@cerberus/react'
export function SlotsDemo() {
return (
<Popover trigger={<Button>Trigger</Button>} size="lg">
<Popover.Header>
<HStack gap="md" pb="lg" w="full">
<Box pos="relative">
<Avatar fallback={<AiAgentInvocation />} gradient="asphodel-dark" />
<Float placement="bottom-end" offsetX="1" offsetY="1">
<Circle
bgColor="success.bg.active"
outline="0.2em solid"
outlineColor="page.surface.initial"
size="8px"
/>
</Float>
</Box>
<Stack direction="column" gap="xs">
<Popover.Title textStyle="heading-xs">Cerby tha Dawg</Popover.Title>
<Popover.Description as="small" color="page.text.100" textStyle="body-xs">
The best boi there is
</Popover.Description>
</Stack>
</HStack>
</Popover.Header>
<Divider color="page.border.initial" thickness="1px" />
<Popover.Body>
<HStack color="page.text.100" gap="sm" w="full">
<Time />
<Text color="page.text.initial">6:66 Local Time</Text>
</HStack>
</Popover.Body>
<Popover.Footer>
<ButtonGroup>
<Button size="sm" usage="outlined-subtle">
<Chat />
Message
</Button>
<Button size="sm" usage="outlined-subtle">
<UserFollow />
Add
</Button>
</ButtonGroup>
</Popover.Footer>
</Popover>
)
}
6:66 Local Time