Lorem, ipsum dolor sit amet consectetur adipisicing elit. Nihil repellat ipsam totam iste, quaerat sapiente.
import { Button, Popover, Portal, Text } from '@fidely-ui/react'
export const PopoverBasics = () => {
return (
<Popover.Root>
<Popover.Trigger asChild>
<Button variant="outline">Click me</Button>
</Popover.Trigger>
<Portal>
<Popover.Positioner>
<Popover.Content>
<Popover.Arrow>
<Popover.ArrowTip />
</Popover.Arrow>
<Text>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Nihil
repellat ipsam totam iste, quaerat sapiente.
</Text>
</Popover.Content>
</Popover.Positioner>
</Portal>
</Popover.Root>
)
}
Usage
import { Popover } from '@fidely-ui/react'<Popover.Root>
<Popover.Trigger />
<Popover.Positioner>
<Popover.Content>
<Popover.CloseTrigger />
<Popover.Arrow>
<Popover.ArrowTip />
</Popover.Arrow>
<Popover.Title />
<Popover.Description />
</Popover.Content>
</Popover.Positioner>
</Popover.Root>Examples
Controlled
Use the open and onOpenChange props to control the visibility of the popover.
This is a Popover with Controlled state
'use client'
import { useState } from 'react'
import { Box, Button, Popover, Portal, Text } from '@fidely-ui/react'
export const PopoverControlled = () => {
const [open, setOpen] = useState(false)
return (
<Popover.Root open={open} onOpenChange={(e) => setOpen(e.open)}>
<Popover.Trigger asChild>
<Button variant="outline">Click me</Button>
</Popover.Trigger>
<Portal>
<Popover.Positioner>
<Popover.Content>
<Popover.Arrow>
<Popover.ArrowTip />
</Popover.Arrow>
<Box>
<Text>This is a Popover with Controlled state</Text>
</Box>
</Popover.Content>
</Popover.Positioner>
</Portal>
</Popover.Root>
)
}
Placement
Use the positioning.placement prop to configure the underlying Floating UI
positioning logic, allowing you to control where the popover appears relative to its trigger.
Fidely UI is a modern, accessible design system built for scalable React applications, focused on clarity, consistency, and developer experience.
import { Box, Button, Popover, Portal, Text } from '@fidely-ui/react'
export const PopoverPositioning = () => {
return (
<Popover.Root positioning={{ placement: 'right', gutter: 12 }}>
<Popover.Trigger asChild>
<Button variant="outline">Click me</Button>
</Popover.Trigger>
<Portal>
<Popover.Positioner>
<Popover.Content maxWidth="260px">
<Popover.Arrow>
<Popover.ArrowTip />
</Popover.Arrow>
<Box>
<Text>
<Text as="strong">Fidely UI</Text> is a modern, accessible
design system built for scalable React applications, focused on
clarity, consistency, and developer experience.
</Text>
</Box>
</Popover.Content>
</Popover.Positioner>
</Portal>
</Popover.Root>
)
}
Offset
Use the positioning.offset prop to adjust the position of the popover content.
import { Box, Button, Popover, Portal } from '@fidely-ui/react'
export const PopoverOffset = () => {
return (
<Popover.Root positioning={{ offset: { crossAxis: 0, mainAxis: 0 } }}>
<Popover.Trigger asChild>
<Button variant="outline">Click show offset</Button>
</Popover.Trigger>
<Portal>
<Popover.Positioner>
<Popover.Content maxWidth="260px">
<Box>Custom offset when open/or trigger</Box>
</Popover.Content>
</Popover.Positioner>
</Portal>
</Popover.Root>
)
}
Form and CloseTrigger
Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid enim qui dignissimos harum in excepturi consectetur corporis eveniet maxime cupiditate. Facere rerum nisi magni repellendus ullam natus in similique repudiandae.
import {
Button,
CloseButton,
Field,
Flex,
HStack,
Input,
Popover,
Portal,
Stack,
Text,
} from '@fidely-ui/react'
export const PopoverCloseWithForm = () => {
return (
<HStack>
{/* one with close button using form */}
<Popover.Root>
<Popover.Trigger asChild>
<Button variant="subtle">Click first</Button>
</Popover.Trigger>
<Portal>
<Popover.Positioner>
<Popover.Content>
<Stack>
<Text>
Lorem ipsum dolor sit amet consectetur adipisicing elit.
Aliquid enim qui dignissimos harum in excepturi consectetur
corporis eveniet maxime cupiditate. Facere rerum nisi magni
repellendus ullam natus in similique repudiandae.
</Text>
<Field.Root>
<Field.Label>Email</Field.Label>
<Input placeholder="Enter email Address" />
</Field.Root>
<Flex justify="flex-end">
<Popover.CloseTrigger asChild>
<Button>Close</Button>
</Popover.CloseTrigger>
</Flex>
</Stack>
</Popover.Content>
</Popover.Positioner>
</Portal>
</Popover.Root>
{/* one with close button with X icon float top-left */}
<Popover.Root>
<Popover.Trigger asChild>
<Button variant="subtle">Click second</Button>
</Popover.Trigger>
<Portal>
<Popover.Positioner>
<Popover.Content>
<Popover.CloseTrigger
asChild
position="absolute"
top="2"
right="2"
>
<CloseButton size="sm" />
</Popover.CloseTrigger>
<Stack>
<Popover.Title textStyle="lg">Hello world</Popover.Title>
<Popover.Description>
Lorem ipsum dolor sit amet consectetur adipisicing elit.
Aliquid enim qui dignissimos harum in excepturi consectetur
corporis eveniet maxime cupiditate. Facere rerum nisi magni
repellendus ullam natus in similique repudiandae.
</Popover.Description>
</Stack>
</Popover.Content>
</Popover.Positioner>
</Portal>
</Popover.Root>
</HStack>
)
}
Custom Background
Use the --popover-bg CSS variable to change the background color of the Popover.Content and its arrow.
Fidely UI
Build modern apps with speed and flexibility
1.2k Downloads
import {
Avatar,
Button,
HStack,
Popover,
Portal,
Stack,
Text,
} from '@fidely-ui/react'
import { LuChartLine } from 'react-icons/lu'
export const PopoverWithBg = () => {
return (
<Popover.Root>
<Popover.Trigger asChild>
<Button variant="outline">Click me</Button>
</Popover.Trigger>
<Portal>
<Popover.Positioner>
<Popover.Content
css={{
'--popover-bg': 'red',
}}
>
<Popover.Arrow>
<Popover.ArrowTip />
</Popover.Arrow>
<Stack gap="4" direction="row">
<Avatar.Root>
<Avatar.Image alt="fidely ui logo" />
<Avatar.Fallback name="Fidely UI" />
</Avatar.Root>
<Stack gap="3">
<Stack gap="1">
<Text textStyle="sm" fontWeight="semibold">
Fidely UI
</Text>
<Text textStyle="sm">
Build modern apps with speed and flexibility
</Text>
</Stack>
<HStack>
<LuChartLine />
<Text textStyle="xs">1.2k Downloads</Text>
</HStack>
</Stack>
</Stack>
</Popover.Content>
</Popover.Positioner>
</Portal>
</Popover.Root>
)
}
Within Dialog
To use the Popover within a Dialog, you need to avoid portalling the Popover.Positioner to the document's body.
/* <Portal> */
<Popover.Positioner>
<Popover.Content>{/* ... */}</Popover.Content>
</Popover.Positioner>
/* </Portal> */If the dialog uses scrollBehavior="inside":
-
Set the popover positioning strategy to fixed to prevent clipping.
-
Enable hideWhenDetached to hide the popover when its trigger scrolls out of view.
<Popover.Root positioning={{ strategy: 'fixed', hideWhenDetached: true }}>
...
</Popover.Root>Props
Root
| Prop | Default | Type | Description |
|---|---|---|---|
autoFocus | true | boolean | Whether to automatically set focus on the first focusable content within the popover when opened. |
closeOnEscape | true | boolean | Whether to close the popover when the escape key is pressed. |
as | — | React.ElementType | The underlying element to render. We don't recommend changing the input to another ElementType. |
asChild | false | boolean | Use the provided child element as the default rendered element, combining their props and behavior. |
closeOnInteractOutside | true | boolean | Whether to close the popover when the user clicks outside of the popover. |
lazyMount | false | boolean | Whether to enable lazy mounting. |
modal | false | boolean | Whether the popover should be modal. When true, interaction with outside elements will be disabled. |
portalled | true | boolean | Whether the popover is portalled. This proxies tabbing behavior regardless of the DOM position. |
skipAnimationOnMount | false | boolean | Whether to allow the initial presence animation. |
unmountOnExit | false | boolean | Whether to unmount on exit. |
unstyled | — | boolean | Whether to remove the component's default styles. |
defaultOpen | — | boolean | The initial open state of the popover when rendered (uncontrolled). |
id | — | string | The unique identifier. |
ids | — | Partial<{}> | The ids of the elements in the popover. |
immediate | — | boolean | Whether to synchronize the present change immediately or defer it to the next frame. |
initialFocusEl | — | () => HTMLElement | null | The element to focus on when the popover is opened. |
onEscapeKeyDown | — | (event: KeyboardEvent) => void | Function called when the escape key is pressed. |
onExitComplete | — | VoidFunction | Function called when the animation ends in the closed state. |
onFocusOutside | — | (event: FocusOutsideEvent) => void | Function called when the focus is moved outside the component. |
onInteractOutside | — | (event: InteractOutsideEvent) => void | Function called when an interaction happens outside the component. |
onOpenChange | — | (details: OpenChangeDetails) => void | Function invoked when the popover opens or closes. |
onPointerDownOutside | — | (event: PointerDownOutsideEvent) => void | Function called when the pointer is pressed down outside the component. |
onRequestDismiss | — | (event: LayerDismissEvent) => void | Function called when this layer is closed due to a parent layer being closed. |
open | — | boolean | The controlled open state of the popover. |
persistentElements | — | (() => Element | null)[] | Returns the persistent elements that should not have pointer-events disabled or trigger the dismiss event. |
positioning | — | PositioningOptions | The user provided options used to position the popover content. |
present | — | boolean | Whether the node is present (controlled by the user). |