diff --git a/src/components/Popover/Popover.jsx b/src/components/Popover/Popover.jsx index d0d24768..913389e8 100644 --- a/src/components/Popover/Popover.jsx +++ b/src/components/Popover/Popover.jsx @@ -12,24 +12,29 @@ export const Popover = React.forwardRef((props, ref) => { const { placement, children, + popoverHelperId, portalId, ...restProps } = props; const PopoverEl = ( -
- {children} - -
+ <> + {!!popoverHelperId &&
} +
+ {children} + +
+ ); if (portalId === null) { @@ -41,6 +46,7 @@ export const Popover = React.forwardRef((props, ref) => { Popover.defaultProps = { placement: 'bottom', + popoverHelperId: null, portalId: null, }; @@ -67,6 +73,12 @@ Popover.propTypes = { 'left-start', 'left-end', ]), + /** + * If set, the popover will become controlled, meaning it will be hidden by default and will need a trigger to open. + * This sets the ID of the internal helper element for the popover. + * Assign the same ID to `popovertarget` of a trigger to make it open and close. + */ + popoverHelperId: PropTypes.string, /** * If set, popover is rendered in the React Portal with that ID. */ diff --git a/src/components/Popover/Popover.module.scss b/src/components/Popover/Popover.module.scss index 1c3d1873..11c95607 100644 --- a/src/components/Popover/Popover.module.scss +++ b/src/components/Popover/Popover.module.scss @@ -49,6 +49,28 @@ } } + // Controlled popover + .controlledPopover { + display: none; + } + + .helper { + position: fixed; + inset: unset; + top: 0; + right: 0; + width: auto; + height: auto; + padding: 0; + border: none; + background: transparent; + pointer-events: none; + } + + .helper:popover-open ~ .controlledPopover { + display: block; + } + // Sides .isRootAtTop { bottom: calc(100% + #{theme.$arrow-gap} - #{theme.$arrow-safe-rendering-overlap}); diff --git a/src/components/Popover/README.md b/src/components/Popover/README.md index dac06ce8..1bae59ad 100644 --- a/src/components/Popover/README.md +++ b/src/components/Popover/README.md @@ -284,6 +284,36 @@ React.createElement(() => { }); ``` +## Controlled Popover + +To make it easier to implement the popover in your app, you can set the `popoverHelperId` prop to the same ID as the `popovertarget` of a trigger. This uses the browser Popover API and will control the popover by closing it when the trigger or backdrop is pressed. + +```docoff-react-preview +React.createElement(() => { + // All inline styles in this example are for demonstration purposes only. + return ( +
+ +
+ ); +}); +``` + ## Forwarding HTML Attributes In addition to the options below in the [component's API](#api) section, you