DocsBlog
  • 1.2.1

  • light

    dark

    system

    Switch mode
  • Cerberus

    Acheron

    Elysium

Get Started
Components
Data Grid
Signals
Styling
Theming

Concepts

OverviewCompositionCerberus ContextTesting

Layout

Aspect RatioBleedBoxCenterContainerDividerFlexFloatGridGroupLink OverlayScrollableStackWrap

Components

AccordionAdmonitionAvatarButtonCarouselCheckboxClipboardCollapsibleComboboxConfirm ModalCTAModalDate PickerDialogFieldFieldsetFile UploaderIcon ButtonInputLoading StatesMenuNotificationsNumber InputPaginationPin InputPopoverNewProgressPrompt ModalRadioRatingSelectSplit ButtonSwitchTableTabsTagTextTextareaToggleTooltip

Utilities

Client OnlyDownload TriggerEnvironmentFeature FlagsFocus TrapForFormat ByteFormat NumberFormat Relative TimeFrameHighlightJSON Tree ViewLocaleLocal StoragePortalPresenceShowsplitPropsTheme

Popover

Used to show detailed information inside a pop-up.

  • npm
  • source
  • recipe
  • Ark
import { Popover } from '@cerberus/react';

Usage

The Popover component is a controlled abstraction of the primitive parts that can be used to show or hide content.

Helper Slots

For advanced layouts, you can utilize the helper slots to streamline styling. Layout related slots correspond to the size variant provided.

Slots

The following slots are available on the Popover object:

ComponentDescription
HeaderUseful for controlling header block styles.
BodyUseful for controlling "body" block styles.
FooterUseful for controlling footer block styles.
TitleUseful for controlling heading-related styles.
DescriptionUseful for controlling body-related styles.

Sizes

The Popover component supports sizes: xs to lg. This changes the padding of the layout slots.

Arrow

Set the usage prop to arrow to show an arrow tip.

Positioning

Use the positioning.placement prop to configure the underlying floating-ui positioning logic.

Lazy Mounting

Use the lazyMounted and/or unmountOnExit prop to defer the mounting of the popover content until it's opened.

Nesting

Popovers can be nested within each other. Each nested popover maintains its own open state and positioning.

Anchor

Use PopoverParts.Anchor to position the popover relative to a different element than the trigger.

Note

Anchor positioning requires the use of PopoverParts since there needs to be an entire layout adjustment.

Customizing

You can customize the Popover using style props and data selectors on any slot primitve.

Guides

Available Size

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);
      }
    }}
  />

Primitives

The layers of the Popover which can be used to create a fully custom solution.

ComponentDescription
PopoverRootThe main container for the popover.
PopoverTriggerThe trigger that toggles the popover content.
PopoverAnchorThe container to anchor the popover content to.
PopoverPositionerThe positioning container for the popover content.
PopoverArrowThe arrow container.
PopoverArrowTipThe actual visible arrow.
PopoverContentThe content container.
PopoverTitleThe heading for a popover.
PopoverDescriptionThe description for a popover.
PopoverCloseTriggerThe close trigger for a popover.
PopoverHeaderThe header for a popover.
PopoverBodyThe body for a popover.
PopoverFooterThe footer for a popover.

Data Attributes

The primitives additionally use the following data attributes for custom styling:

NameValueDescription
data-scopepopoverThe scope of the components.
data-partrootThe root layer of the scope.
data-parttriggerThe trigger layer of the scope.
data-partanchorThe anchor layer of the scope.
data-partanchor-tipThe anchor-tip layer of the scope.
data-partpositionerThe positioner layer of the scope.
data-partarrowThe arrow layer of the scope.
data-partarrow-tipThe arrow-tip layer of the scope.
data-partcontentThe content layer of the scope.
data-parttitleThe title layer of the scope.
data-partdescriptionThe description layer of the scope.
data-partheaderThe header layer of the scope.
data-partbodyThe body layer of the scope.
data-partfooterThe footer layer of the scope.

API

Root Props

PropTypeRequiredDescription
autoFocusbooleanNoWhether to automatically set focus on the first focusable content within the popover when opened.
closeOnEscapebooleanNoWhether to close the popover when the escape key is pressed.
closeOnInteractOutsidebooleanNoWhether to close the popover when the user clicks outside of the popover.
defaultOpenbooleanNoThe initial open state of the popover when rendered. Use when you don't need to control the open state of the popover.
idstringNoThe unique identifier of the machine.
idsPartial<PrimitiveSlots>NoThe ids of the elements in the popover. Useful for composition.
immediatebooleanNoWhether to synchronize the present change immediately or defer it to the next frame
initialFocusEl() => HTMLElement | nullNoThe element to focus on when the popover is opened.
lazyMountbooleanNoWhether to enable lazy mounting
modalbooleanNoWhether 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) => voidNoFunction called when the escape key is pressed
onExitCompleteVoidFunctionNoFunction called when the animation ends in the closed state
onFocusOutside(event: FocusOutsideEvent) => voidNoFunction called when the focus is moved outside the component
onInteractOutside(event: InteractOutsideEvent) => voidNoFunction called when an interaction happens outside the component
onOpenChange(details: OpenChangeDetails) => voidNoFunction invoked when the popover opens or closes
onPointerDownOutside(event: PointerDownOutsideEvent) => voidNoFunction called when the pointer is pressed down outside the component
onRequestDismiss(event: LayerDismissEvent) => voidNoFunction called when this layer is closed due to a parent layer being closed
openbooleanNoThe controlled open state of the popover
persistentElements(() => Element | null)[]NoReturns the persistent elements that: should not have pointer-events disabled, should not trigger the dismiss event
portalledbooleanNoWhether the popover is portalled. This will proxy the tabbing behavior regardless of the DOM position of the popover content.
positioningPositioningOptionsNoThe user provided options used to position the popover content
presentbooleanNoWhether the node is present (controlled by the user)
skipAnimationOnMountbooleanNoWhether to allow the initial presence animation.
unmountOnExitbooleanNoWhether to unmount on exit.

Anchor Props

PropTypeRequiredDescription
asChildbooleanNoUse the provided child element as the default rendered element, combining their props and behavior.

Arrow Props

PropTypeRequiredDescription
asChildbooleanNoUse the provided child element as the default rendered element, combining their props and behavior.

Arrow CSS Variables

VariableDescription
--arrow-sizeThe size of the arrow
--arrow-size-halfHalf the size of the arrow
--arrow-backgroundUse this variable to style the arrow background
--arrow-offsetThe offset position of the arrow

ArrowTip Props

PropTypeRequiredDescription
asChildbooleanNoUse the provided child element as the default rendered element, combining their props and behavior.

CloseTrigger Props

PropTypeRequiredDescription
asChildbooleanNoUse the provided child element as the default rendered element, combining their props and behavior.

Content Props

PropTypeRequiredDescription
asChildbooleanNoUse the provided child element as the default rendered element, combining their props and behavior.

Content Data Attributes

AttributeValue
[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

Content CSS Variables

VariableDescription
--layer-indexThe index of the dismissable in the layer stack
--nested-layer-countThe number of nested popovers

Description Props

PropTypeRequiredDescription
asChildbooleanNoUse the provided child element as the default rendered element, combining their props and behavior.

Indicator Props

PropTypeRequiredDescription
asChildbooleanNoUse the provided child element as the default rendered element, combining their props and behavior.

Indicator Data Attributes

AttributeValue
[data-scope]popover
[data-part]indicator
[data-state]"open" | "closed"

Positioner Props

PropTypeRequiredDescription
asChildbooleanNoUse the provided child element as the default rendered element, combining their props and behavior.

Positioner CSS Variables

VariableDescription
--reference-widthThe width of the reference element
--reference-heightThe height of the root
--available-widthThe available width in viewport
--available-heightThe available height in viewport
--xThe x position for transform
--yThe y position for transform
--z-indexThe z-index value
--transform-originThe transform origin for animations

RootProvider Props

PropTypeRequiredDescription
valueUsePopoverReturnYes
immediatebooleanNoWhether to synchronize the present change immediately or defer it to the next frame
lazyMountbooleanNoWhether to enable lazy mounting
onExitCompleteVoidFunctionNoFunction called when the animation ends in the closed state
presentbooleanNoWhether the node is present (controlled by the user)
skipAnimationOnMountbooleanNoWhether to allow the initial presence animation.
unmountOnExitbooleanNoWhether to unmount on exit.

Title Props

PropTypeRequiredDescription
asChildbooleanNoUse the provided child element as the default rendered element, combining their props and behavior.

Trigger Props

PropTypeRequiredDescription
asChildbooleanNoUse the provided child element as the default rendered element, combining their props and behavior.

Trigger Data Attributes

AttributeValue
[data-scope]popover
[data-part]trigger
[data-placement]The placement of the trigger
[data-state]"open" | "closed"

On this page

  • Edit this page on Github
Copy
'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>
  )
}
Copy
'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>
  )
}
Copy
'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>
  )
}
Copy
'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>
  )
}
Copy
'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>
  )
}
Copy
'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>
  )
}
Copy
'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>
  )
}
Copy
'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>
  )
}
Copy
'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>
  )
}
Everything is content...
Everything is content...
Everything is content...
This is the parent popover content.
This is the nested popover content.
This is anchored to the input.
This is a custom popover
That is fully built from scratch
Footer sturf
Everything is content...
This is a xs popover
This is a sm popover
This is a md popover
This is a lg popover
Cerby tha Dawg
The best boi there is

6:66 Local Time