Popover
An overlay that displays additional information or options when triggered.
import { XIcon } from 'lucide-react'
import { Box, Stack } from 'styled-system/jsx'
import { Button } from '~/components/ui/button'
import { IconButton } from '~/components/ui/icon-button'
import { Popover } from '~/components/ui/popover'
export const Demo = (props: Popover.RootProps) => {
  return (
    <Popover.Root {...props}>
      <Popover.Trigger asChild>
        <Button>Open Popover</Button>
      </Popover.Trigger>
      <Popover.Positioner>
        <Popover.Content>
          <Popover.Arrow>
            <Popover.ArrowTip />
          </Popover.Arrow>
          <Stack gap="1">
            <Popover.Title>Favorite Framework</Popover.Title>
            <Popover.Description>
              Tell us what is your favorite framework and why you love to use it.
            </Popover.Description>
          </Stack>
          <Box position="absolute" top="1" right="1">
            <Popover.CloseTrigger asChild>
              <IconButton aria-label="Close Popover" variant="ghost" size="sm">
                <XIcon />
              </IconButton>
            </Popover.CloseTrigger>
          </Box>
        </Popover.Content>
      </Popover.Positioner>
    </Popover.Root>
  )
}
import { XIcon } from 'lucide-solid'
import { Box, Stack } from 'styled-system/jsx'
import { Button } from '~/components/ui/button'
import { IconButton } from '~/components/ui/icon-button'
import { Popover } from '~/components/ui/popover'
export const Demo = (props: Popover.RootProps) => {
  return (
    <Popover.Root {...props}>
      <Popover.Trigger
        asChild={(triggerProps) => <Button {...triggerProps()}>Open Popover</Button>}
      />
      <Popover.Positioner>
        <Popover.Content>
          <Popover.Arrow>
            <Popover.ArrowTip />
          </Popover.Arrow>
          <Stack gap="1">
            <Popover.Title>Favorite Framework</Popover.Title>
            <Popover.Description>
              Tell us what is your favorite framework and why you love to use it.
            </Popover.Description>
          </Stack>
          <Box position="absolute" top="1" right="1">
            <Popover.CloseTrigger
              asChild={(closeProps) => (
                <IconButton aria-label="Close Popover" variant="ghost" size="sm" {...closeProps()}>
                  <XIcon />
                </IconButton>
              )}
            />
          </Box>
        </Popover.Content>
      </Popover.Positioner>
    </Popover.Root>
  )
}
Usage
import { Popover } from '~/components/ui/popover'Installation
npx @park-ui/cli components add popover1
Add Styled Primitive
Copy the code snippet below into ~/components/ui/styled/popover.tsx
'use client'
import type { Assign } from '@ark-ui/react'
import { Popover } from '@ark-ui/react/popover'
import { type PopoverVariantProps, popover } from 'styled-system/recipes'
import type { ComponentProps, HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from './utils/create-style-context'
const { withRootProvider, withContext } = createStyleContext(popover)
export type RootProviderProps = ComponentProps<typeof RootProvider>
export const RootProvider = withRootProvider<
  Assign<Popover.RootProviderProps, PopoverVariantProps>
>(Popover.RootProvider)
export type RootProps = ComponentProps<typeof Root>
export const Root = withRootProvider<Assign<Popover.RootProps, PopoverVariantProps>>(Popover.Root)
export const Anchor = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, Popover.AnchorBaseProps>
>(Popover.Anchor, 'anchor')
export const Arrow = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, Popover.ArrowBaseProps>
>(Popover.Arrow, 'arrow')
export const ArrowTip = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, Popover.ArrowTipBaseProps>
>(Popover.ArrowTip, 'arrowTip')
export const CloseTrigger = withContext<
  HTMLButtonElement,
  Assign<HTMLStyledProps<'button'>, Popover.CloseTriggerBaseProps>
>(Popover.CloseTrigger, 'closeTrigger')
export const Content = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, Popover.ContentBaseProps>
>(Popover.Content, 'content')
export const Description = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, Popover.DescriptionBaseProps>
>(Popover.Description, 'description')
export const Indicator = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, Popover.IndicatorBaseProps>
>(Popover.Indicator, 'indicator')
export const Positioner = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, Popover.PositionerBaseProps>
>(Popover.Positioner, 'positioner')
export const Title = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, Popover.TitleBaseProps>
>(Popover.Title, 'title')
export const Trigger = withContext<
  HTMLButtonElement,
  Assign<HTMLStyledProps<'button'>, Popover.TriggerBaseProps>
>(Popover.Trigger, 'trigger')
export { PopoverContext as Context } from '@ark-ui/react/popover'
import { type Assign, Popover } from '@ark-ui/solid'
import type { ComponentProps } from 'solid-js'
import { type PopoverVariantProps, popover } from 'styled-system/recipes'
import type { HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from './utils/create-style-context'
const { withRootProvider, withContext } = createStyleContext(popover)
export type RootProviderProps = ComponentProps<typeof RootProvider>
export const RootProvider = withRootProvider<
  Assign<Popover.RootProviderProps, PopoverVariantProps>
>(Popover.RootProvider)
export type RootProps = ComponentProps<typeof Root>
export const Root = withRootProvider<Assign<Popover.RootProps, PopoverVariantProps>>(Popover.Root)
export const Anchor = withContext<Assign<HTMLStyledProps<'div'>, Popover.AnchorBaseProps>>(
  Popover.Anchor,
  'anchor',
)
export const Arrow = withContext<Assign<HTMLStyledProps<'div'>, Popover.ArrowBaseProps>>(
  Popover.Arrow,
  'arrow',
)
export const ArrowTip = withContext<Assign<HTMLStyledProps<'div'>, Popover.ArrowTipBaseProps>>(
  Popover.ArrowTip,
  'arrowTip',
)
export const CloseTrigger = withContext<
  Assign<HTMLStyledProps<'button'>, Popover.CloseTriggerBaseProps>
>(Popover.CloseTrigger, 'closeTrigger')
export const Content = withContext<Assign<HTMLStyledProps<'div'>, Popover.ContentBaseProps>>(
  Popover.Content,
  'content',
)
export const Description = withContext<
  Assign<HTMLStyledProps<'div'>, Popover.DescriptionBaseProps>
>(Popover.Description, 'description')
export const Indicator = withContext<Assign<HTMLStyledProps<'div'>, Popover.IndicatorBaseProps>>(
  Popover.Indicator,
  'indicator',
)
export const Positioner = withContext<Assign<HTMLStyledProps<'div'>, Popover.PositionerBaseProps>>(
  Popover.Positioner,
  'positioner',
)
export const Title = withContext<Assign<HTMLStyledProps<'div'>, Popover.TitleBaseProps>>(
  Popover.Title,
  'title',
)
export const Trigger = withContext<Assign<HTMLStyledProps<'button'>, Popover.TriggerBaseProps>>(
  Popover.Trigger,
  'trigger',
)
export { PopoverContext as Context } from '@ark-ui/solid'
No snippet found2
Add Re-Export
To improve the developer experience, re-export the styled primitives in~/components/ui/popover.tsx.
export * as Popover from './styled/popover'
export * as Popover from './styled/popover'
3
Integrate Recipe
If you're not using @park-ui/preset, add the following recipe to yourpanda.config.ts:
import { popoverAnatomy } from '@ark-ui/anatomy'
import { defineSlotRecipe } from '@pandacss/dev'
export const popover = defineSlotRecipe({
  className: 'popover',
  slots: popoverAnatomy.keys(),
  base: {
    positioner: {
      position: 'relative',
    },
    content: {
      background: 'bg.default',
      borderRadius: 'l3',
      boxShadow: 'lg',
      display: 'flex',
      flexDirection: 'column',
      maxWidth: 'sm',
      zIndex: 'popover',
      p: '4',
      _open: {
        animation: 'fadeIn 0.25s ease-out',
      },
      _closed: {
        animation: 'fadeOut 0.2s ease-out',
      },
      _hidden: {
        display: 'none',
      },
    },
    title: {
      fontWeight: 'medium',
      textStyle: 'sm',
    },
    description: {
      color: 'fg.muted',
      textStyle: 'sm',
    },
    closeTrigger: {
      color: 'fg.muted',
    },
    arrow: {
      '--arrow-size': 'var(--sizes-3)',
      '--arrow-background': 'var(--colors-bg-default)',
    },
    arrowTip: {
      borderTopWidth: '1px',
      borderLeftWidth: '1px',
    },
  },
})