Popover
An overlay that displays additional information or options when triggered.
Usage
Favorite Framework
Tell us what is your favorite framework and why you love to use it.
import { XIcon } from 'lucide-react'
import { Box, Stack } from 'styled-system/jsx'
import { Button, IconButton, Popover } from '~/components/ui'
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>
)
}
Installation
npx @park-ui/cli components add popover
1
Styled Primitive
Copy the code snippet below into ~/components/ui/primitives/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 '~/lib/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 '~/lib/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 found
Extend ~/components/ui/primitives/index.ts
with the following line:
export * as Popover from './popover'
2
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',
},
},
})