Popover

Import
import { Popover } from "reshaped";
import type { PopoverProps } from "reshaped";

You can use Popover with any interactive element on the page by passing its attributes and adding the content you want to render.

<Popover>
  <Popover.Trigger>
    {(attributes) => <Button attributes={attributes}>Trigger popover</Button>}
  </Popover.Trigger>
  <Popover.Content>Popover content</Popover.Content>
</Popover>

Popover opens after clicking the trigger element, but you can change this using the triggerType property.

<Popover triggerType="hover">
  <Popover.Trigger>
    {(attributes) => (
      <Button attributes={attributes}>Trigger popover on hover</Button>
    )}
  </Popover.Trigger>
  <Popover.Content>Popover content</Popover.Content>
</Popover>

You can define the position where you want to display the Popover. If it doesn't fit on the screen, it will automatically pick a better position within the viewport.

<Popover position="bottom-end">
  <Popover.Trigger>
    {(attributes) => <Button attributes={attributes}>Trigger popover</Button>}
  </Popover.Trigger>
  <Popover.Content>Popover content</Popover.Content>
</Popover>

If you want to ignore the viewport boundaries and always show the Popover using a specific position value, you can lock it with the forcePosition property. This can be useful when using Popover to build dropdown menus.

<Popover position="bottom-end" forcePosition>
  <Popover.Trigger>
    {(attributes) => <Button attributes={attributes}>Trigger popover</Button>}
  </Popover.Trigger>
  <Popover.Content>Popover content</Popover.Content>
</Popover>

You can control the width of the Popover with the width property. You can pass a specific px or percent value, including CSS variables, to define the size.

<Popover width="calc(var(--rs-unit-x1) * 100)">
  <Popover.Trigger>
    {(attributes) => <Button attributes={attributes}>Trigger popover</Button>}
  </Popover.Trigger>
  <Popover.Content>Popover content</Popover.Content>
</Popover>

Popover comes with default padding in its content area, which you can customize with the padding property. For example, you can remove it entirely by setting padding to 0.

<Popover padding={0}>
  <Popover.Trigger>
    {(attributes) => <Button attributes={attributes}>Trigger popover</Button>}
  </Popover.Trigger>
  <Popover.Content>
    <View backgroundColor="neutral-faded" height={50} />
  </Popover.Content>
</Popover>

If you need to add a close button to the Popover content, you can use it with the Dismissible utility.

function Demo() {
  const { activate, deactivate, active } = useToggle();

  return (
    <Popover active={active} onOpen={activate} onClose={deactivate}>
      <Popover.Trigger>
        {(attributes) => (
          <Button attributes={attributes}>Trigger popover</Button>
        )}
      </Popover.Trigger>
      <Popover.Content>
        <Dismissible onClose={deactivate} closeAriaLabel="Close popover">
          <View backgroundColor="neutral-faded" height={50} />
        </Dismissible>
      </Popover.Content>
    </Popover>
  );
}

You can either pass a literal width value like 200px or use the trigger value to align the Popover content width with its trigger. This is helpful when using the fullWidth Button component or Select / TextField with Popover.

<Popover width="trigger">
  <Popover.Trigger>
    {(attributes) => (
      <Select
        name="animal"
        placeholder="Select an animal"
        inputAttributes={attributes}
      />
    )}
  </Popover.Trigger>
  <Popover.Content></Popover.Content>
</Popover>

If you pass the defaultActive flag to the component, it will open the Popover on mount and use its internal state afterward.

If you pass the active flag, the controlled mode will be activated, and you will need to manage the component's state manually. This means you must control the state using onOpen and onClose handlers, allowing you to add custom logic before updating the state.

You can remove most of the Popover content styles by using the headless variant. This is useful when you want to customize the content's appearance. For example, you can add a border color or show an image component without rendering a card wrapper around it.

You can apply custom styles by rendering another component inside the Popover.Content or by adding a className to it. When using the headless variant, you still have access to all Popover properties.

<Popover variant="headless">
  <Popover.Trigger>
    {(attributes) => <Button attributes={attributes}>Show a photo</Button>}
  </Popover.Trigger>
  <Popover.Content>
    <Image
      src="/img/examples/image-retina.webp"
      alt="Canyon rock"
      borderRadius="medium"
      width="200px"
    />
  </Popover.Content>
</Popover>
  • It's essential to pass the attributes provided by the Popover component to your interactive trigger component. This ensures that all user events and aria attributes are assigned correctly.

  • Popover traps the focus in its content area, but you can control how this is applied with the trapFocusMode property. It applies a regular focus trap with Tab key navigation enabled by default. You can switch it to action-menu or content-menu modes to make it work like a listbox or a regular content area with links.