Popover
View .mdA popover is a small surface that appears when someone interacts with a component to give nonessential, contextual information without blocking them.
Default
Loading interactive example. Full source is available below.
View example 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.
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.
// 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.
// 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.
// 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.
// 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.
// 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.
// 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.
// 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.
// 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.
// 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.
// 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.
// 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.
// 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.
// 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;