# Popover
> The Popover component displays floating informative and actionable content in relation to a target.

## Import

```js
import { Popover } from '@volue/wave-react';

// you may also access Popover's context via hook:
// import { usePopoverContext } from '@volue/wave-react';
```

Popover is a compound component that consists of multiple parts:

- `Popover.Root`: The wrapper that contains all the parts of a popover and provides context for its children.
- `Popover.Trigger`: The button that opens the popover.
- `Popover.Content`: The container for the popover's content.
- `Popover.Close`: The button that closes the popover.

## Examples

### Basic

`Popover` works in an uncontrolled way by default, meaning each `Popover` component instance is responsible for managing its own state internally.

<Callout variant="tip">

The `Popover.Trigger` component can be instructed via `as` prop to render _as_ something else. In our case we want to render it as a `<Button>` component.

</Callout>

```jsx
<Popover.Root>
  <Popover.Trigger as={Button} variant="outline">
    {'Open Popover'}
  </Popover.Trigger>
  <Popover.Content>
    {'Popover content'}
    <Box marginTop="spacingM">
      <Popover.Close as={Button}>{'Close'}</Popover.Close>
    </Box>
  </Popover.Content>
</Popover.Root>
```

### Controlled Popover

You can easily make the popover controlled, by passing your own state to `isOpen` prop.
`onIsOpenChange` handler is called when the state of the popover changes, allowing you to sync state.

```jsx
() => {
  const [state, setState] = React.useState(false);

  return (
    <Popover.Root isOpen={state} onIsOpenChange={setState}>
      <Popover.Trigger as={Button} variant="outline">
        {'Open Popover'}
      </Popover.Trigger>
      <Popover.Content>
        {'Popover content'}
        <Box marginTop="spacingM">
          <Popover.Close as={Button}>{'Close'}</Popover.Close>
        </Box>
      </Popover.Content>
    </Popover.Root>
  );
};
```

### Popover with header and body

```jsx
<Popover.Root>
  <Popover.Trigger as={Button} variant="outline">
    {'Open Popover'}
  </Popover.Trigger>
  <Popover.Content>
    <Flex marginBottom="spacingM">
      <Popover.Title>Popover title</Popover.Title>
      <Popover.Close
        as={Button}
        variant="ghost"
        shape="circle"
        size="small"
        withLoneIcon
        aria-label="Close"
        marginLeft="auto"
      >
        <SvgIcon iconName="close" />
      </Popover.Close>
    </Flex>
    <Box marginY="spacingM">{'Are you sure you want to do this?'}</Box>
    <Popover.Close as={Button}>{'Yes'}</Popover.Close>
  </Popover.Content>
</Popover.Root>
```

### Sizes

You can set the size of the popover by passing `size` prop to `Popover.Content` with `small` or `medium` value. The default value is `medium`.

```jsx
<Flex>
  <Popover.Root>
    <Popover.Trigger as={Button} variant="outline">
      {'Medium Popover'}
    </Popover.Trigger>
    <Popover.Content size="medium">
      {'Popover content'}
      <Box marginTop="spacingM">
        <Popover.Close as={Button}>{'Close'}</Popover.Close>
      </Box>
    </Popover.Content>
  </Popover.Root>
  <Popover.Root>
    <Popover.Trigger as={Button} variant="outline" size="small">
      {'Small Popover'}
    </Popover.Trigger>
    <Popover.Content size="small">
      {'Popover content'}
      <Box marginTop="spacingS">
        <Popover.Close as={Button} size="small">
          {'Close'}
        </Popover.Close>
      </Box>
    </Popover.Content>
  </Popover.Root>
</Flex>
```

### Customizing placement

Popover uses [Positioner](/components/utility/positioner) under the hood. Use `placement` prop to customize placement of the `Popover.Content`.

```jsx
<Popover.Root>
  <Popover.Trigger as={Button} variant="outline">
    {'Open Popover'}
  </Popover.Trigger>
  <Popover.Content placement="top_left">
    {'Popover content'}
    <Box marginTop="spacingM">
      <Popover.Close as={Button}>{'Close'}</Popover.Close>
    </Box>
  </Popover.Content>
</Popover.Root>
```

### Popover with form example

```jsx
<Popover.Root>
  <Popover.Trigger as={Button} variant="outline">
    {'Open Popover'}
  </Popover.Trigger>
  <Popover.Content placement="right" css={{ width: '24rem' }}>
    <Flex as="form" flow="column" gap="spacingM">
      <FormField.Root as={Flex} flow="column">
        <FormField.Label>{'First name'}</FormField.Label>
        <TextInput />
      </FormField.Root>
      <FormField.Root as={Flex} flow="column">
        <FormField.Label>{'Last Name'}</FormField.Label>
        <TextInput />
      </FormField.Root>
      <Flex main="end">
        <Popover.Close as={Button} variant="ghost">
          {'Cancel'}
        </Popover.Close>
        <Button type="submit">{'Submit'}</Button>
      </Flex>
    </Flex>
  </Popover.Content>
</Popover.Root>
```

### With custom anchor

By default, `Popover` uses its trigger as an "anchor" for positioning. With `Popover.Anchor` you can anchor the content to another element.

```jsx
<Popover.Root>
  <Flex wrap="wrap">
    <Popover.Anchor>
      <TextInput />
    </Popover.Anchor>
    <Popover.Trigger as={Button} variant="outline">
      {'Open Popover'}
    </Popover.Trigger>
  </Flex>
  <Popover.Content css={{ minWidth: '10ch', maxWidth: '25ch' }}>
    {'Popover content with text input as a position reference.'}
  </Popover.Content>
</Popover.Root>
```

---

## Accessibility features

<ul>
  <li iconName="check">

When the popover opens, focus is sent into the popover and set to the first tabbable element. Focus stays trapped within the popover until close is requested. After closing, focus is restored back to the trigger element.

  </li>
  <li iconName="check">

Clicking away closes the overlay.

  </li>
  <li iconName="check">

Pressing ESC closes the overlay.

  </li>
  <li iconName="check">

The popover is portaled (via [Portal utility](/components/utility/portal)) to the end of `document.body` to break it out of the source order.

  </li>
</ul>

---

## API Reference

### Popover.Root

| Name             | Type                        | Default | Description                                                                                             | Required |
| ---------------- | --------------------------- | ------- | ------------------------------------------------------------------------------------------------------- | -------- |
| `isOpen`         | `boolean`                   | `false` | The controlled open state of the popover. Use in conjunction with `onIsOpenChange`.                     |          |
| `defaultIsOpen`  | `boolean`                   |         | The open state of the popover when it's first rendered. Use when you do not need to control open state. |          |
| `onIsOpenChange` | `(isOpen: boolean) => void` |         | Event handler called when the open state of the popover changes.                                        |          |

### Popover.Trigger

| Name  | Type                                                      | Default  | Description                                                                                                                                                                                                                                                                                  | Required |
| ----- | --------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`  | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `button` | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css` | `StitchesCss`                                             |          | Apply styles directly to a component in a similar way how you would define inline styles. Wave uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |

### Popover.Content

| Name                       | Type                                                                                                     | Default         | Description                                                                                                                                                                                                                                                                                  | Required |
| -------------------------- | -------------------------------------------------------------------------------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`                       | `keyof JSX.IntrinsicElements \| React.ComponentType<any>`                                                | `div`           | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`                      | `StitchesCss`                                                                                            |                 | Apply styles directly to a component in a similar way how you would define inline styles. Wave uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |
| `size`                     | `"medium" \| "small"`                                                                                    | `"medium"`      | The size of the popover content container. `padding` prop might override this.                                                                                                                                                                                                               |          |
| `padding`                  | `SpacingToken`                                                                                           |                 | Sets `padding` to one of the corresponding [spacing tokens](/tokens/white-space).                                                                                                                                                                                                            |          |
| `placement`                | `"top" \| "top_left" \| "top_right" \| "bottom" \| "bottom_left" \| "bottom_right" \| "left" \| "right"` | `"bottom_left"` | Placement of the popover. Smart positioning might override this.                                                                                                                                                                                                                             |          |
| `enablePositionAutoUpdate` | `boolean`                                                                                                | `true`          | Controls whether to automatically update the position of the content so it remains anchored to the trigger.                                                                                                                                                                                  |          |
| `anchorOffset`             | `number`                                                                                                 |                 | Distance from the trigger to the popover.                                                                                                                                                                                                                                                    |          |
| `onExitComplete`           | `() => void`                                                                                             | `() => void`    | Event handler called when the popover has completed animating out.                                                                                                                                                                                                                           |          |
| `onCloseAutoFocus`         | `(event: Event) => void`                                                                                 |                 | Event handler called when focus moves to the trigger after closing. It can be prevented with `event.preventDefault`.                                                                                                                                                                         |          |

### Popover.Title

<Callout variant="tip">

In addition to the props below, you can pass [Heading props](/components/typography/heading#api-reference).

</Callout>

| Name  | Type                                                      | Default  | Description                                                                                                                                                                                                                                                                                  | Required |
| ----- | --------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`  | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `button` | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css` | `StitchesCss`                                             |          | Apply styles directly to a component in a similar way how you would define inline styles. Wave uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |

### Popover.Close

| Name  | Type                                                      | Default  | Description                                                                                                                                                                                                                                                                                  | Required |
| ----- | --------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`  | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `button` | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css` | `StitchesCss`                                             |          | Apply styles directly to a component in a similar way how you would define inline styles. Wave uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |

### Popover.Anchor

<Callout variant="tip">

An optional element to position the `Popover.Content` against.

</Callout>

| Name  | Type                                                      | Default | Description                                                                                                                                                                                                                                                                                  | Required |
| ----- | --------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`  | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `div`   | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css` | `StitchesCss`                                             |         | Apply styles directly to a component in a similar way how you would define inline styles. Wave uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |
