# Popover

- Page: https://jiguang132.com/resources/mantine/docs/popover
- Resource: Mantine Core (https://jiguang132.com/resources/mantine.md)
- All guides: https://jiguang132.com/resources/mantine/docs.md

Install: `npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1`

## Version and compatibility

Pinned Mantine Core 9.7.1 requires React and React DOM `^19.2.0` and matching `@mantine/hooks@9.7.1`, from the installed npm package's peerDependencies. Do not force it into React 18 or another incompatible version. Explain upgrade impact and agree on a plan with the project owner; do not hide conflicts with --force/--legacy-peer-deps. The native Provider enables `theme.respectReducedMotion` and uses `forceColorScheme` for light/dark.

## Use case

Show content anchored to a target.

## Native props used by this example

These props are extracted from the local typechecked JSX and grouped by their owning native component. This is not an exhaustive prop list; see pinned source signatures and inheritance below.

This minimal example passes children only; no additional props are invented. Optional props are in the source reference.

## Interaction and state checks

Current scenarios: Default. Check actual behavior after selecting supported disabled/error/read-only scenarios; components without those native states do not receive invented universal props. Verify keyboard focus and exits, then connect changed values through the native callback signature.

## Business integration boundary

Demo content/state is local, without server persistence, authorization or fetching. A static display component is not a completed business workflow.

## Host setup

Install pinned @mantine/core and @mantine/hooks, import @mantine/core/styles.css at the entry and use MantineProvider. The example's theme/variant are JGuang-authored host props, not universal native component APIs; forceColorScheme synchronizes the app theme. Native implementation source is a reading reference: use npm exports rather than copying internal engines. This batch covers Core, not dates/charts/forms extension packages. Detailed upstream prose remains English.


## Runnable usage

```tsx
import { useState } from 'react';
import * as M from '@mantine/core';
import '@mantine/core/styles.css';


function ComponentPreview({ variant = 'Default' }: { variant?: string }) {
const content = <M.Text>Build something beautiful / 构建美好的界面</M.Text>;
return <M.Popover><M.Popover.Target><M.Button>Toggle popover</M.Button></M.Popover.Target><M.Popover.Dropdown>{content}</M.Popover.Dropdown></M.Popover>;
}
export default function Example({ variant = 'Default', theme = 'light' }: { variant?: string; theme?: 'light' | 'dark' }) {
return <M.MantineProvider forceColorScheme={theme} theme={{ respectReducedMotion: true }}><ComponentPreview variant={variant} /></M.MantineProvider>;
}

```


## Preview states

Default

The example uses the native Mantine API. For supported input demos, change the local variant to Disabled, Invalid or Read only; these are example labels, not new component props. Keep the documented data, controlled values, stores and compound children when adapting the example.



## Usage



## Controlled

You can control the Popover state with the `opened` and `onChange` props:

```tsx
import { useState } from 'react';
import { Button, Popover } from '@mantine/core';

function Demo() {
  const [opened, setOpened] = useState(false);
  return (
    <Popover opened={opened} onChange={setOpened}>
      <Popover.Target>
        <Button onClick={() => setOpened((o) => !o)}>
          Toggle popover
        </Button>
      </Popover.Target>

      <Popover.Dropdown>Dropdown</Popover.Dropdown>
    </Popover>
  );
}
```

Controlled example with mouse events:



## Focus trap

If you need to use interactive elements (inputs, buttons, etc.) inside `Popover.Dropdown`, set the `trapFocus` prop:



## Inline elements

Enable the `inline` middleware to use `Popover` with inline elements:



## Same width

Set the `width="target"` prop to make the Popover dropdown take the same width as the target element:



## offset

Set the `offset` prop to a number to change the dropdown position relative to the target element.
This way you can control the dropdown offset on the main axis only.



To control offset on both axes, pass an object with `mainAxis` and `crossAxis` properties:



## Middlewares

You can enable or disable [Floating UI](https://floating-ui.com/) middlewares with the
`middlewares` prop:

- [shift](https://floating-ui.com/docs/shift) middleware shifts the dropdown to keep it in view. It is enabled by default.
- [flip](https://floating-ui.com/docs/flip) middleware changes the placement of the dropdown to keep it in view. It is enabled by default.
- [inline](https://floating-ui.com/docs/inline) middleware improves positioning for inline reference elements that span over multiple lines. It is disabled by default.
- [size](https://floating-ui.com/docs/size) middleware manipulates the dropdown size. It is disabled by default.

Example of turning off `shift` and `flip` middlewares:

```tsx
import { Popover } from '@mantine/core';

function Demo() {
  return (
    <Popover
      middlewares={{ flip: false, shift: false }}
      position="bottom"
    >
      {/* Popover content */}
    </Popover>
  );
}
```

## Customize middleware options

To customize [Floating UI](https://floating-ui.com/) middleware options, pass them as
an object to the `middlewares` prop. For example, to change the [shift](https://floating-ui.com/docs/shift)
middleware padding to `20px`, use the following configuration:

```tsx
import { Popover } from '@mantine/core';

function Demo() {
  return (
    <Popover
      middlewares={{ shift: { padding: 20 } }}
      position="bottom"
    >
      {/* Popover content */}
    </Popover>
  );
}
```

## Dropdown arrow

Set the `withArrow` prop to add an arrow to the dropdown. The arrow is a `div` element rotated with `transform: rotate(45deg)`.

The `arrowPosition` prop determines how the arrow is positioned relative to the target element when `position` is set to `*-start` and `*-end` values on the `Popover` component.
By default, the value is `center` – the arrow is positioned in the center of the target element if it is possible.

If you change `arrowPosition` to `side`, then the arrow will be positioned on the side of the target element,
and you will be able to control the arrow offset with the `arrowOffset` prop. Note that when `arrowPosition` is set to `center`,
the `arrowOffset` prop is ignored.



## With overlay

Set the `withOverlay` prop to add an overlay behind the dropdown. You can pass additional
configuration to the [Overlay](/core/overlay/) component with the `overlayProps` prop:



## Hide detached

Use the `hideDetached` prop to configure how the dropdown behaves when the target
element is hidden with styles (`display: none`, `visibility: hidden`, etc.),
removed from the DOM, or when the target element is scrolled out of the viewport.

By default, `hideDetached` is enabled – the dropdown is hidden with the target element.
You can change this behavior with `hideDetached={false}`. To see the difference, try to scroll
the root element of the following demo:



## Disabled

Set the `disabled` prop to prevent `Popover.Dropdown` from rendering:



## Click outside

By default, `Popover` closes when you click outside of the dropdown. To disable this behavior, set `closeOnClickOutside={false}`.

If an element outside of the popover stops propagation of the event, the popover does not close when that element is clicked.
Set the `clickOutsideCapture` prop to register listeners in the capture phase and close the popover in this case as well.

You can configure events that are used for click-outside detection with the `clickOutsideEvents` prop.
By default, `Popover` listens to `mousedown` and `touchstart` events. You can change it to any other
events, for example, `mouseup` and `touchend`:



## onDismiss

If you need to control the opened state, but still want to close the popover on outside clicks
and escape key presses, use the `onDismiss` prop:

```tsx
import { useState } from 'react';
import { Button, Popover } from '@mantine/core';

function Demo() {
  const [opened, setOpened] = useState(false);
  return (
    <Popover
      opened={opened}
      onDismiss={() => setOpened(false)}
    >
      <Popover.Target>
        <Button onClick={() => setOpened((o) => !o)}>
          Toggle popover
        </Button>
      </Popover.Target>

      <Popover.Dropdown>Dropdown</Popover.Dropdown>
    </Popover>
  );
}
```

## Initial focus

Popover uses the [FocusTrap](/core/focus-trap/) component to manage focus.
Add the `data-autofocus` attribute to the element that should receive initial focus:

```tsx
import { Popover } from '@mantine/core';

function Demo() {
  return (
    <Popover>
      <Popover.Target>
        <button type="button">Target</button>
      </Popover.Target>
      <Popover.Dropdown>
        <input />
        <input data-autofocus />
        <input />
      </Popover.Dropdown>
    </Popover>
  );
}
```


## Context menu

Use `Popover.ContextMenu` to open the dropdown at the cursor position on right-click.
It replaces `Popover.Target` and wraps the element that should respond to the `contextmenu`
event – the browser's default context menu is suppressed, and `Popover.Dropdown` is positioned
at the cursor. Right-clicking again repositions the dropdown to the new coordinates.
`Popover.Dropdown` can contain any content. Set `disabled` to restore the browser's default
context menu:



### Touch devices

On touch devices (most notably iOS Safari, which does not fire the `contextmenu` event),
the dropdown is opened with a long-press instead. Use the `longPressDelay` prop to control
how long the element must be pressed before the dropdown opens, `500`ms by default. To
prevent the native text-selection callout from appearing under the dropdown on touch
devices, `Popover.ContextMenu` disables text selection (`user-select: none`) on the wrapped
element.

## Nested popovers

Nested popovers require children rendering without [Portal](/core/portal/). Usually, you
should disable the portal with props of the component that renders popover content. For example,
[Select](/core/select/) has a `comboboxProps={{ withinPortal: false }}` prop. Check the documentation
of the component that you are using to render popover content to find out how to disable the portal.
If the portal is not disabled, outside clicks will close all popovers.

Example of disabling the portal in [Select](/core/select/) and [DatePickerInput](/dates/date-picker-input/)
components:



## Accessibility

Popover follows [WAI-ARIA recommendations](https://www.w3.org/TR/wai-aria-practices-1.2/#dialog_modal):

- Dropdown element has `role="dialog"` and `aria-labelledby="target-id"` attributes
- Target element has `aria-haspopup="dialog"`, `aria-expanded`, `aria-controls="dropdown-id"` attributes

An uncontrolled Popover will be accessible only when used with a `button` element or component that renders it ([Button](/core/button/), [ActionIcon](/core/action-icon/), etc.).
Other elements will not support `Space` and `Enter` key presses.

## Keyboard interactions



## Source-backed parameter reference

Implementation signatures and types are generated from the pinned local source. Optional props, native inherited types, union branches and never exclusions are preserved. A forwardRef implementation's ref is a React reference, not an additional business prop.


```ts
Popover(_props: PopoverProps)
```



```ts
export type PopoverStylesNames = 'dropdown' | 'arrow' | 'overlay';

export type PopoverCssVariables = {
  dropdown: '--popover-radius' | '--popover-shadow';
};

export interface __PopoverProps {
  /** Dropdown position relative to the target element @default 'bottom' */
  position?: FloatingPosition;

  /** Offset of the dropdown element @default 8 */
  offset?: number | FloatingAxesOffsets;

  /** Called when dropdown position changes */
  onPositionChange?: (position: FloatingPosition) => void;

  /** Called when dropdown closes */
  onClose?: () => void;

  /** Called when the popover is dismissed by clicking outside or by pressing escape */
  onDismiss?: () => void;

  /** Called when dropdown opens */
  onOpen?: () => void;

  /** If set, the dropdown is not unmounted from the DOM when hidden. `display: none` styles are added instead. */
  keepMounted?: boolean;

  /**
   * Controls how the dropdown is hidden when `keepMounted` is set:
   * `'activity'` – hidden with React 19 `Activity` component,
   * `'display-none'` – hidden with `display: none` styles
   * @default 'activity'
   */
  keepMountedMode?: 'activity' | 'display-none';

  /** Props passed down to the `Transition` component. Use to configure duration and animation type. @default { duration: 150, transition: 'fade' } */
  transitionProps?: TransitionOverride;

  /** Called when exit transition ends */
  onExitTransitionEnd?: () => void;

  /** Called when enter transition ends */
  onEnterTransitionEnd?: () => void;

  /** Dropdown width, or `'target'` to make dropdown width the same as target element @default 'max-content' */
  width?: PopoverWidth;

  /** Floating ui middlewares to configure position handling @default { flip: true, shift: true, inline: false } */
  middlewares?: PopoverMiddlewares;

  /** Determines whether component should have an arrow @default false */
  withArrow?: boolean;

  /** Determines whether the overlay should be displayed when the dropdown is opened @default false */
  withOverlay?: boolean;

  /** Props passed down to `Overlay` component */
  overlayProps?: OverlayProps & ElementProps<'div'>;

  /** Arrow size in px @default 7 */
  arrowSize?: number;

  /** Arrow offset in px @default 5 */
  arrowOffset?: number;

  /** Arrow `border-radius` in px @default 0 */
  arrowRadius?: number;

  /** Arrow position */
  arrowPosition?: ArrowPosition;

  /** Determines whether dropdown should be rendered within the `Portal` @default true */
  withinPortal?: boolean;

  /** Props to pass down to the `Portal` when `withinPortal` is true */
  portalProps?: BasePortalProps;

  /** Dropdown `z-index` @default 300 */
  zIndex?: string | number;

  /** Key of `theme.radius` or any valid CSS value to set border-radius @default theme.defaultRadius */
  radius?: MantineRadius;

  /** Key of `theme.shadows` or any other valid CSS `box-shadow` value */
  shadow?: MantineShadow;

  /** If set, popover dropdown will not be rendered */
  disabled?: boolean;

  /** Determines whether focus should be automatically returned to control when dropdown closes @default false */
  returnFocus?: boolean;

  /** Changes floating ui [position strategy](https://floating-ui.com/docs/usefloating#strategy) @default 'absolute' */
  floatingStrategy?: FloatingStrategy;

  /** If set, the dropdown is hidden when the element is hidden with styles or not visible on the screen @default true */
  hideDetached?: boolean;

  /** If `true`, the dropdown picks its side on open (flip runs once, preferring the `position` prop) and then never changes side — scrolling, resizing, and content size changes will not flip the dropdown. The side is recalculated fresh on the next open. Does not affect the `shift` middleware. Set to `false` to keep flip active and allow the dropdown to re-flip on every change. @default true */
  preventPositionChangeWhenVisible?: boolean;

  /** If set, outside click listeners are registered in the capture phase @default false */
  clickOutsideCapture?: boolean;
}

export interface PopoverProps extends __PopoverProps, StylesApiProps<PopoverFactory> {
  __staticSelector?: string;

  /** `Popover.Target` and `Popover.Dropdown` components */
  children?: React.ReactNode;

  /** Initial opened state for uncontrolled component */
  defaultOpened?: boolean;

  /** Controlled dropdown opened state */
  opened?: boolean;

  /** Called with current state when dropdown opens or closes */
  onChange?: (opened: boolean) => void;

  /** Determines whether dropdown should be closed on outside clicks @default true */
  closeOnClickOutside?: boolean;

  /** Events that trigger outside clicks */
  clickOutsideEvents?: string[];

  /** Determines whether focus should be trapped within dropdown @default false */
  trapFocus?: boolean;

  /** Determines whether dropdown should be closed when `Escape` key is pressed @default true */
  closeOnEscape?: boolean;

  /** Id base to create accessibility connections */
  id?: string;

  /** Determines whether dropdown and target elements should have accessible roles @default true */
  withRoles?: boolean;
}

export type PopoverFactory = Factory<{
  props: PopoverProps;
  stylesNames: PopoverStylesNames;
  vars: PopoverCssVariables;
}>;

export type ElementProps<
  ElementType extends React.ElementType,
  PropsToOmit extends string = never,
> = Omit<React.ComponentProps<ElementType>, 'style' | PropsToOmit>;
```


### Native and external types

External types remain defined by React or native dependencies, not manually expanded into guessed props. The installed version's TypeScript definitions are authoritative.


```ts
FloatingPosition
FloatingAxesOffsets
TransitionOverride
PopoverWidth
PopoverMiddlewares
OverlayProps
React.ElementType
Omit<React.ComponentProps<ElementType>, 'style' | PropsToOmit>
React.ComponentProps<ElementType>
ElementType
PropsToOmit
ArrowPosition
BasePortalProps
MantineRadius
MantineShadow
FloatingStrategy
StylesApiProps<PopoverFactory>
Factory<{
  props: PopoverProps;
  stylesNames: PopoverStylesNames;
  vars: PopoverCssVariables;
}>
React.ReactNode
```

---

Index of all JGuang resources: https://jiguang132.com/llms.txt
