Default

Loading interactive example. Full source is available below.

View example source
Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { PopoverProps } from "@coreai-ds/react-components";
import * as React from 'react';
import { Popover } from "@coreai-ds/react-components";
import { PopoverTrigger } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { PopoverSurface } from "@coreai-ds/react-components";

export const Default = (props: Omit<PopoverProps, 'children'>) => {
    const ExampleContent = (): React.JSX.Element => (<div className="popover-default-example__content">
        <h3 className="popover-default-example__content-header">Popover content</h3>

        <div>This is some popover content</div>
      </div>);
    const styles = /* css */ `
      .popover-default-example__content-header {
        margin-top: 0;
      }
    `;
    return (<>
        <style>{styles}</style>
        <Popover {...props}>
          <PopoverTrigger disableButtonEnhancement>
            <Button>Popover trigger</Button>
          </PopoverTrigger>

          <PopoverSurface className="popover-default-example" tabIndex={-1}>
            <ExampleContent />
          </PopoverSurface>
        </Popover>
      </>);
};

export default Default;

Resources

Best practices

Do

  • Use popovers for brief, nonessential contextual information.
  • Limit dimensions so the popover does not obscure important UI.
  • Position it so its relationship to the trigger or context is clear.

Don't

  • Nest popovers.
  • Put task-essential or repeated information in a popover.
  • Use a popover for a complex layout or blocking interaction; use a dialog.

Behavior and states

  • Popovers grow to accommodate their content by default.
  • Set overflow to scroll when content exceeds the available dimensions.
  • Position popovers so people can tell what the information relates to.
  • Don’t nest popovers.
  • Popovers can have structured content and interactive components.
  • If you need to show a more complex layout or block the page behind, try a dialog.
  • For unstructured plain text, try a tooltip.
API referenceGenerated CoreAI prop and type summaries

API

Generated CoreAI prop summaries, not replacement type declarations. Most native DOM/event and ARIA props are omitted. ? means optional; JSDoc shows defaults, deprecations, and conditional requirements. Defaults assume the standard CoreAI provider.

Popover API

Wrapper component that manages state for a PopoverTrigger and a PopoverSurface components.

interface PopoverProps {
  /**
   * A popover can appear styled with brand or inverted.
   * When not specified, the default style is used.
   */
  appearance?: "brand" | "inverted";

  /**
   * Can contain two children including `PopoverTrigger` and `PopoverSurface`.
   * Alternatively can only contain `PopoverSurface` if using a custom `target`.
   */
  children: JSXElement | [JSXElement, JSXElement];

  /**
   * Flag to close the Popover when an iframe outside a PopoverSurface is focused
   * @default true
   */
  closeOnIframeFocus?: boolean;

  /**
   * Close when scroll outside of it
   * @default false
   */
  closeOnScroll?: boolean;

  /**
   * Used to set the initial open state of the Popover in uncontrolled mode
   * @default false
   */
  defaultOpen?: boolean;

  /**
   * Enables standard behavior according to the [HTML dialog spec](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/showModal)
   * where the focus trap involves setting outside elements inert,
   * making navigation leak from the trapped area back to the browser toolbar and vice-versa.
   * @default false
   */
  inertTrapFocus?: boolean;

  /**
   * Popovers are rendered out of DOM order on `document.body` by default, use this to render the popover in DOM order
   * @default false
   */
  inline?: boolean;

  /**
   * Must be used with the `trapFocus` prop
   * Enables older Fluent UI focus trap behavior where the user
   * cannot tab into the window outside of the document. This is now
   * non-standard behavior according to the [HTML dialog spec](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/showModal)
   * where the focus trap involves setting outside elements inert.
   * @deprecated this behavior is default provided now, to opt-out of it in favor of standard behavior use the `inertTrapFocus` property
   */
  legacyTrapFocus?: boolean;

  /**
   * Where the portal children are mounted on DOM
   * @default a new element on document.body without any styling
   */
  mountNode?: HTMLElement | { element?: HTMLElement | null; className?: string; } | null | undefined;

  /**
   * Sets the delay for closing popover on mouse leave
   */
  mouseLeaveDelay?: number;

  /**
   * Call back when the component requests to change value
   * The `open` value is used as a hint when directly controlling the component
   */
  onOpenChange?: ((e: OpenPopoverEvents, data: OnOpenChangeData) => void);

  /**
   * Controls the opening of the Popover
   * @default false
   */
  open?: boolean;

  /**
   * Flag to open the Popover as a context menu. Disables all other interactions
   * @default false
   */
  openOnContext?: boolean;

  /**
   * Flag to open the Popover by hovering the trigger
   * @default false
   */
  openOnHover?: boolean;

  /**
   * Configures the position of the Popover.
   * Explore [Positioning docs](https://react.fluentui.dev/?path=/docs/concepts-developer-positioning-components--docs) for more options.
   */
  positioning?: PositioningShorthand;

  /**
   * Determines popover padding and arrow size
   * @default medium
   */
  size?: "small" | "medium" | "large";

  /**
   * Slot for the surface motion animation.
   * For more information refer to the [Motion docs page](https://react.fluentui.dev/?path=/docs/motion-motion-slot--docs).
   */
  surfaceMotion?: PresenceMotionSlotProps | null;

  /**
   * Should trap focus
   * @default false
   */
  trapFocus?: boolean;

  /**
   * By default Popover focuses the first focusable element in PopoverSurface on open.
   * Specify `disableAutoFocus` to prevent this behavior.
   * @default false
   */
  unstable_disableAutoFocus?: boolean;

  /**
   * Display an arrow pointing to the target.
   * @default false
   */
  withArrow?: boolean;
}

PopoverProvider API

interface PopoverProviderProps {
  children?: ReactNode;

  value: PopoverContextValue;
}

PopoverSurface API

PopoverSurface component renders react children in a positioned box

interface PopoverSurfaceProps {
  as?: "div";

  children?: any;

  className?: string;

  ref?: Ref<HTMLDivElement>;

  style?: CSSProperties;
}

PopoverTrigger API

Wraps a trigger element as an only child and adds the necessary event handling to open a popover.

interface PopoverTriggerProps {
  children?: ReactElement<any, string | JSXElementConstructor<any>> | ((props: PopoverTriggerChildProps<ARIAButtonType, {}>) => ReactElement<any, string | JSXElementConstructor<any>> | null) | null;

  /**
   * Disables internal trigger mechanism that ensures a child provided will be a compliant ARIA button.
   * @default false
   */
  disableButtonEnhancement?: boolean;
}

Implementation

CoreAI 0.12.0; Fluent 9.74.9.

Setup and dependencies.

Import components from @coreai-ds/react-components. CoreAI guidance above takes precedence over API demonstration examples.

Anchor To Custom Target

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import type { PositioningImperativeRef } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { Popover } from "@coreai-ds/react-components";
import { PopoverTrigger } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { PopoverSurface } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    container: {
        display: 'flex',
        gap: '10px',
    },
    contentHeader: {
        marginTop: '0',
    },
});

const ExampleContent = () => {
    const styles = useStyles();
    return (<div>
      <h3 className={styles.contentHeader}>Popover content</h3>

      <div>This is some popover content</div>
      <Button>Action</Button>
    </div>);
};

export const AnchorToCustomTarget = (): JSXElement => {
    const positioningRef = React.useRef<PositioningImperativeRef>(null);
    const buttonRef = React.useCallback((el: HTMLButtonElement | null) => {
        positioningRef.current?.setTarget(el);
    }, [positioningRef]);
    const styles = useStyles();
    return (<div className={styles.container}>
      <Popover positioning={{ positioningRef }}>
        <PopoverTrigger disableButtonEnhancement>
          <Button>Popover trigger</Button>
        </PopoverTrigger>

        <PopoverSurface>
          <ExampleContent />
        </PopoverSurface>
      </Popover>

      <Button ref={buttonRef}>Custom target</Button>
    </div>);
};

export default AnchorToCustomTarget;

Appearance

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { Popover } from "@coreai-ds/react-components";
import { PopoverTrigger } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { PopoverSurface } from "@coreai-ds/react-components";
import * as React from 'react';

const useLayoutStyles = makeStyles({
    root: {
        display: 'flex',
        flexDirection: 'column',
        rowGap: tokens.spacingVerticalMNudge,
    },
});

const useStyles = makeStyles({
    contentHeader: {
        marginTop: '0',
    },
});

const ExampleContent = () => {
    const styles = useStyles();
    return (<div>
      <h3 className={styles.contentHeader}>Popover content</h3>

      <div>This is some popover content</div>
      <Button>Action</Button>
    </div>);
};

export const Appearance = (): JSXElement => {
    const layoutStyles = useLayoutStyles();
    return (<div className={layoutStyles.root}>
      <Popover>
        <PopoverTrigger disableButtonEnhancement>
          <Button>Default appearance Popover trigger</Button>
        </PopoverTrigger>

        <PopoverSurface>
          <ExampleContent />
        </PopoverSurface>
      </Popover>

      <Popover appearance="brand">
        <PopoverTrigger disableButtonEnhancement>
          <Button>Brand appearance Popover trigger</Button>
        </PopoverTrigger>

        <PopoverSurface>
          <ExampleContent />
        </PopoverSurface>
      </Popover>

      <Popover appearance="inverted">
        <PopoverTrigger disableButtonEnhancement>
          <Button>Inverted appearance Popover trigger</Button>
        </PopoverTrigger>

        <PopoverSurface>
          <ExampleContent />
        </PopoverSurface>
      </Popover>
    </div>);
};

export default Appearance;

Controlling Open And Close

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import * as React from 'react';
import type { PopoverProps } from "@coreai-ds/react-components";
import type { CheckboxProps } from "@coreai-ds/react-components";
import { Popover } from "@coreai-ds/react-components";
import { PopoverTrigger } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { PopoverSurface } from "@coreai-ds/react-components";
import { Checkbox } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    contentHeader: {
        marginTop: '0',
    },
    container: {
        display: 'flex',
        flexDirection: 'column',
    },
});

const ExampleContent = () => {
    const styles = useStyles();
    return (<div>
      <h3 className={styles.contentHeader}>Popover content</h3>

      <div>This is some popover content</div>
      <Button>Action</Button>
    </div>);
};

export const ControllingOpenAndClose = (): JSXElement => {
    const styles = useStyles();
    const [open, setOpen] = React.useState(false);
    const handleOpenChange: PopoverProps['onOpenChange'] = (e, data) => setOpen(data.open || false);
    const onChange: CheckboxProps['onChange'] = (e, { checked }) => {
        setOpen(checked as boolean);
    };
    return (<div className={styles.container}>
      <Popover open={open} onOpenChange={handleOpenChange}>
        <PopoverTrigger disableButtonEnhancement>
          <Button>Controlled trigger</Button>
        </PopoverTrigger>
        <PopoverSurface>
          <ExampleContent />
        </PopoverSurface>
      </Popover>
      <Checkbox value="open" name="state" label="open" checked={open} onChange={onChange}/>
    </div>);
};

export default ControllingOpenAndClose;

Custom Trigger

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { Popover } from "@coreai-ds/react-components";
import { PopoverTrigger } from "@coreai-ds/react-components";
import * as React from 'react';
import type { PopoverTriggerChildProps } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { PopoverSurface } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";

const CustomPopoverTrigger = React.forwardRef<HTMLButtonElement, Partial<PopoverTriggerChildProps>>((props, ref) => {
    return (<Button {...props} ref={ref}>
      Custom Trigger
    </Button>);
});

const useStyles = makeStyles({
    contentHeader: {
        marginTop: '0',
    },
});

const ExampleContent = () => {
    const styles = useStyles();
    return (<div>
      <h3 className={styles.contentHeader}>Popover content</h3>

      <div>This is some popover content</div>
      <Button>Action</Button>
    </div>);
};

export const CustomTrigger = (): JSXElement => {
    return (<Popover>
      <PopoverTrigger>
        <CustomPopoverTrigger />
      </PopoverTrigger>
      <PopoverSurface>
        <ExampleContent />
      </PopoverSurface>
    </Popover>);
};

export default CustomTrigger;

Internal Update Content

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import type { PopoverProps } from "@coreai-ds/react-components";
import { Popover } from "@coreai-ds/react-components";
import { PopoverTrigger } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { PopoverSurface } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    contentHeader: {
        marginTop: '0',
    },
});

const ExampleContent = () => {
    const styles = useStyles();
    return (<div>
      <h3 className={styles.contentHeader}>Popover content</h3>

      <div>This is some popover content</div>
    </div>);
};

export const InternalUpdateContent = (): JSXElement => {
    const [visible, setVisible] = React.useState(false);
    const focusRef = React.useRef<HTMLAnchorElement>(null);
    const changeContent = () => setVisible(true);
    const onOpenChange: PopoverProps['onOpenChange'] = (e, data) => {
        if (data.open === false) {
            setVisible(false);
        }
    };
    React.useEffect(() => {
        if (visible) {
            focusRef.current?.focus();
        }
    }, [visible]);
    return (<Popover onOpenChange={onOpenChange}>
      <PopoverTrigger disableButtonEnhancement>
        <Button>Popover trigger</Button>
      </PopoverTrigger>

      <PopoverSurface>
        <ExampleContent />

        {visible ? (<div>
            The second panel content{' '}
            <Link href="#" ref={focusRef}>
              and a link
            </Link>
          </div>) : (<div>
            <Button onClick={changeContent}>Action</Button>
          </div>)}
      </PopoverSurface>
    </Popover>);
};

export default InternalUpdateContent;

Motion Custom

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { Popover } from "@coreai-ds/react-components";
import { createPresenceComponent } from "@coreai-ds/react-components";
import { fadeAtom } from "@fluentui/react-motion-components-preview";
import { blurAtom } from "@fluentui/react-motion-components-preview";
import { PopoverTrigger } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { PopoverSurface } from "@coreai-ds/react-components";
import * as React from 'react';

const FadeInBlurOut = createPresenceComponent({
    enter: fadeAtom({ duration: 500, direction: 'enter' }),
    exit: [fadeAtom({ duration: 500, direction: 'exit' }), blurAtom({ duration: 500, direction: 'exit' })],
});

export const MotionCustom = (): JSXElement => (<Popover surfaceMotion={{
        children: (_, motionProps) => <FadeInBlurOut {...motionProps}/>,
    }}>
    <PopoverTrigger disableButtonEnhancement>
      <Button>Open popover</Button>
    </PopoverTrigger>

    <PopoverSurface>
      <h3 style={{ marginTop: 0 }}>Popover content</h3>
      <p>This popover fades in and blurs out.</p>
      <Button>Action</Button>
    </PopoverSurface>
  </Popover>);

export default MotionCustom;

Motion Disabled

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { Popover } from "@coreai-ds/react-components";
import { PopoverTrigger } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { PopoverSurface } from "@coreai-ds/react-components";
import * as React from 'react';

export const MotionDisabled = (): JSXElement => (<Popover surfaceMotion={null}>
    <PopoverTrigger disableButtonEnhancement>
      <Button>Open popover</Button>
    </PopoverTrigger>

    <PopoverSurface>
      <h3 style={{ marginTop: 0 }}>Popover content</h3>
      <p>This popover has motion disabled</p>
      <Button>Action</Button>
    </PopoverSurface>
  </Popover>);

export default MotionDisabled;

Nested Popovers

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { Popover } from "@coreai-ds/react-components";
import { PopoverTrigger } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { PopoverSurface } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    contentHeader: {
        marginTop: '0',
    },
});

const SecondNestedPopover = () => {
    const styles = useStyles();
    const id = useId();
    return (<Popover trapFocus>
      <PopoverTrigger disableButtonEnhancement>
        <Button>Second nested trigger</Button>
      </PopoverTrigger>

      <PopoverSurface aria-labelledby={id}>
        <div>
          <h3 id={id} className={styles.contentHeader}>
            Popover content
          </h3>

          <div>This is some popover content</div>
        </div>
        <Button>Second nested button</Button>
      </PopoverSurface>
    </Popover>);
};

const FirstNestedPopover = () => {
    const styles = useStyles();
    const id = useId();
    return (<Popover trapFocus>
      <PopoverTrigger disableButtonEnhancement>
        <Button>First nested trigger</Button>
      </PopoverTrigger>

      <PopoverSurface aria-labelledby={id}>
        <div>
          <h3 id={id} className={styles.contentHeader}>
            Popover content
          </h3>

          <div>This is some popover content</div>
        </div>
        <Button>First nested button</Button>
        <SecondNestedPopover />
        <SecondNestedPopover />
      </PopoverSurface>
    </Popover>);
};

export const NestedPopovers = (): JSXElement => {
    const styles = useStyles();
    const id = useId();
    return (<Popover trapFocus>
      <PopoverTrigger disableButtonEnhancement>
        <Button>Root trigger</Button>
      </PopoverTrigger>

      <PopoverSurface>
        <div>
          <h3 id={id} className={styles.contentHeader}>
            Popover content
          </h3>

          <div>This is some popover content</div>
        </div>
        <Button>Root button</Button>
        <FirstNestedPopover />
      </PopoverSurface>
    </Popover>);
};

export default NestedPopovers;

Non Interactive Content

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { Popover } from "@coreai-ds/react-components";
import { PopoverTrigger } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { PopoverSurface } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    contentHeader: {
        marginTop: '0',
    },
});

export const NonInteractiveContent = (): JSXElement => {
    const styles = useStyles();
    const headingId = useId('popover-heading');
    return (<Popover>
      <PopoverTrigger disableButtonEnhancement>
        <Button>Popover trigger</Button>
      </PopoverTrigger>

      <PopoverSurface tabIndex={-1} aria-labelledby={headingId}>
        <h3 id={headingId} className={styles.contentHeader}>
          Popover content
        </h3>
        <p>This is some non-interactive popover content.</p>
      </PopoverSurface>
    </Popover>);
};

export default NonInteractiveContent;

Trapping Focus

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { Popover } from "@coreai-ds/react-components";
import { PopoverTrigger } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { PopoverSurface } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    contentHeader: {
        marginTop: '0',
    },
});

export const TrappingFocus = (): JSXElement => {
    const styles = useStyles();
    const id = useId();
    return (<Popover trapFocus>
      <PopoverTrigger disableButtonEnhancement>
        <Button>Popover trigger</Button>
      </PopoverTrigger>

      <PopoverSurface aria-labelledby={id}>
        <div>
          <h3 id={id} className={styles.contentHeader}>
            Popover content
          </h3>

          <div>This is some popover content</div>
        </div>

        <div>
          <Button>Action</Button>
          <Button>Action</Button>
        </div>
      </PopoverSurface>
    </Popover>);
};

export default TrappingFocus;

With Arrow

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { Popover } from "@coreai-ds/react-components";
import { PopoverTrigger } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { PopoverSurface } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    contentHeader: {
        marginTop: '0',
    },
});

const ExampleContent = () => {
    const styles = useStyles();
    return (<div>
      <h3 className={styles.contentHeader}>Popover content</h3>

      <div>This popover has an arrow pointing to its target</div>
      <Button>Action</Button>
    </div>);
};

export const WithArrow = (): JSXElement => (<Popover withArrow>
    <PopoverTrigger disableButtonEnhancement>
      <Button>Popover trigger</Button>
    </PopoverTrigger>

    <PopoverSurface>
      <ExampleContent />
    </PopoverSurface>
  </Popover>);

export default WithArrow;

With Arrow Autosize

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { Popover } from "@coreai-ds/react-components";
import { PopoverTrigger } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { PopoverSurface } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import * as React from 'react';

const useContentStyles = makeStyles({
    root: {
        boxSizing: 'border-box',
        padding: '16px',
        overflowY: 'auto',
        height: '100%',
    },
    header: {
        marginTop: '0',
    },
});

const ExampleContent = () => {
    const styles = useContentStyles();
    return (<div className={styles.root}>
      <h3 className={styles.header}>Popover content</h3>

      <Button>Action</Button>

      <div>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum semper, nulla at pretium pulvinar, erat nibh
        ultricies risus, eget tincidunt neque nisl non nunc. Integer tempus augue nec facilisis suscipit. Aenean finibus
        orci id turpis euismod, sit amet varius neque porta. Curabitur et urna vel orci luctus dictum. Mauris sed eros
        euismod, cursus justo non, facilisis nibh. Aliquam blandit leo ut nisl tincidunt, sit amet ultrices lacus
        molestie. Phasellus aliquet massa non vestibulum condimentum. Vivamus posuere, ligula eu pharetra fringilla,
        lorem leo elementum risus, vitae tempor odio purus sed libero. Vestibulum porta nisl a metus ultricies, vel
        dignissim lectus facilisis. Etiam interdum mi a suscipit aliquet. Nullam rhoncus molestie purus, id porta neque
        consequat vitae. Sed id aliquam elit. Praesent nunc libero, vulputate vitae porta nec, venenatis sed augue.
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum semper, nulla at pretium pulvinar, erat nibh
        ultricies risus, eget tincidunt neque nisl non nunc. Integer tempus augue nec facilisis suscipit. Aenean finibus
        orci id turpis euismod, sit amet varius neque porta. Curabitur et urna vel orci luctus dictum. Mauris sed eros
        euismod, cursus justo non, facilisis nibh. Aliquam blandit leo ut nisl tincidunt, sit amet ultrices lacus
        molestie. Phasellus aliquet massa non vestibulum condimentum. Vivamus posuere, ligula eu pharetra fringilla,
        lorem leo elementum risus, vitae tempor odio purus sed libero. Vestibulum porta nisl a metus ultricies, vel
        dignissim lectus facilisis. Etiam interdum mi a suscipit aliquet. Nullam rhoncus molestie purus, id porta neque
        consequat vitae. Sed id aliquam elit. Praesent nunc libero, vulputate vitae porta nec, venenatis sed augue.
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum semper, nulla at pretium pulvinar, erat nibh
        ultricies risus, eget tincidunt neque nisl non nunc. Integer tempus augue nec facilisis suscipit. Aenean finibus
        orci id turpis euismod, sit amet varius neque porta. Curabitur et urna vel orci luctus dictum. Mauris sed eros
        euismod, cursus justo non, facilisis nibh. Aliquam blandit leo ut nisl tincidunt, sit amet ultrices lacus
        molestie. Phasellus aliquet massa non vestibulum condimentum. Vivamus posuere, ligula eu pharetra fringilla,
        lorem leo elementum risus, vitae tempor odio purus sed libero. Vestibulum porta nisl a metus ultricies, vel
        dignissim lectus facilisis. Etiam interdum mi a suscipit aliquet. Nullam rhoncus molestie purus, id porta neque
        consequat vitae. Sed id aliquam elit. Praesent nunc libero, vulputate vitae porta nec, venenatis sed augue.
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum semper, nulla at pretium pulvinar, erat nibh
        ultricies risus, eget tincidunt neque nisl non nunc. Integer tempus augue nec facilisis suscipit. Aenean finibus
        orci id turpis euismod, sit amet varius neque porta. Curabitur et urna vel orci luctus dictum. Mauris sed eros
        euismod, cursus justo non, facilisis nibh. Aliquam blandit leo ut nisl tincidunt, sit amet ultrices lacus
        molestie. Phasellus aliquet massa non vestibulum condimentum. Vivamus posuere, ligula eu pharetra fringilla,
        lorem leo elementum risus, vitae tempor odio purus sed libero. Vestibulum porta nisl a metus ultricies, vel
        dignissim lectus facilisis. Etiam interdum mi a suscipit aliquet. Nullam rhoncus molestie purus, id porta neque
        consequat vitae. Sed id aliquam elit. Praesent nunc libero, vulputate vitae porta nec, venenatis sed augue.
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum semper, nulla at pretium pulvinar, erat nibh
        ultricies risus, eget tincidunt neque nisl non nunc. Integer tempus augue nec facilisis suscipit. Aenean finibus
        orci id turpis euismod, sit amet varius neque porta. Curabitur et urna vel orci luctus dictum. Mauris sed eros
        euismod, cursus justo non, facilisis nibh. Aliquam blandit leo ut nisl tincidunt, sit amet ultrices lacus
        molestie. Phasellus aliquet massa non vestibulum condimentum. Vivamus posuere, ligula eu pharetra fringilla,
        lorem leo elementum risus, vitae tempor odio purus sed libero. Vestibulum porta nisl a metus ultricies, vel
        dignissim lectus facilisis. Etiam interdum mi a suscipit aliquet. Nullam rhoncus molestie purus, id porta neque
        consequat vitae. Sed id aliquam elit. Praesent nunc libero, vulputate vitae porta nec, venenatis sed augue.
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum semper, nulla at pretium pulvinar, erat nibh
        ultricies risus, eget tincidunt neque nisl non nunc. Integer tempus augue nec facilisis suscipit. Aenean finibus
        orci id turpis euismod, sit amet varius neque porta. Curabitur et urna vel orci luctus dictum. Mauris sed eros
        euismod, cursus justo non, facilisis nibh. Aliquam blandit leo ut nisl tincidunt, sit amet ultrices lacus
        molestie. Phasellus aliquet massa non vestibulum condimentum. Vivamus posuere, ligula eu pharetra fringilla,
        lorem leo elementum risus, vitae tempor odio purus sed libero. Vestibulum porta nisl a metus ultricies, vel
        dignissim lectus facilisis. Etiam interdum mi a suscipit aliquet. Nullam rhoncus molestie purus, id porta neque
        consequat vitae. Sed id aliquam elit. Praesent nunc libero, vulputate vitae porta nec, venenatis sed augue.
      </div>
    </div>);
};

export const WithArrowAutosize = (): JSXElement => (<Popover withArrow positioning={{ autoSize: true }}>
    <PopoverTrigger disableButtonEnhancement>
      <Button>Popover trigger</Button>
    </PopoverTrigger>

    {/* 1. Reset the overflow behavior on `PopoverSurface` to avoid clipping of arrow */}
    <PopoverSurface style={{ overflow: 'visible', padding: 0 }}>
      {/* 2. Set the height of the popover content to 100% to fill the available space and allow scrolling */}
      <ExampleContent />
    </PopoverSurface>
  </Popover>);

export default WithArrowAutosize;

Without Trigger

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { useId } from "@coreai-ds/react-components";
import type { PositioningImperativeRef } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { useRestoreFocusTarget } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Popover } from "@coreai-ds/react-components";
import { PopoverSurface } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    container: {
        display: 'flex',
        gap: '10px',
    },
    contentHeader: {
        marginTop: '0',
    },
});

export const WithoutTrigger = (): JSXElement => {
    const [open, setOpen] = React.useState(false);
    const headerId = useId();
    const buttonRef = React.useRef<HTMLButtonElement>(null);
    const positioningRef = React.useRef<PositioningImperativeRef>(null);
    const styles = useStyles();
    const restoreFocusTargetAttribute = useRestoreFocusTarget();
    React.useEffect(() => {
        if (buttonRef.current) {
            positioningRef.current?.setTarget(buttonRef.current);
        }
    }, [buttonRef, positioningRef]);
    return (<div className={styles.container}>
      <Button {...restoreFocusTargetAttribute} ref={buttonRef} onClick={() => setOpen(s => !s)}>
        Toggle popover
      </Button>
      <Popover onOpenChange={(e, data) => {
            if (e.target === buttonRef.current) {
                // Ignore events that are triggered by the button to avoid re-opening the popover
                return;
            }
            setOpen(data.open);
        }} trapFocus open={open} positioning={{ positioningRef }}>
        <PopoverSurface aria-labelledby={headerId}>
          <div>
            <h3 id={headerId} className={styles.contentHeader}>
              Popover content
            </h3>

            <div>This is some popover content</div>
          </div>

          <div>
            <Button>Action</Button>
            <Button>Action</Button>
          </div>
        </PopoverSurface>
      </Popover>
    </div>);
};

export default WithoutTrigger;