Skip to main content
Light Dark System

Popover

<cw-popover> | CwPopover
Since 1.5 experimental

Popovers display rich content anchored to a trigger, positioned with floating-ui and rendered via the native Popover API’s top layer — a good fit for content that doesn’t belong in a tooltip (hover-only) or a dropdown (menu-focused).

Popovers consist of a trigger and a panel. Activating the trigger shows the panel, anchored to it; clicking outside the panel or pressing Escape closes it again.

Popovers are a good fit for content that doesn’t belong in a tooltip (hover-only, not meant for rich or interactive content) or a dropdown (built around a menu). Forms, previews, and other rich content anchored to a trigger are all good candidates.

Toggle This is a popover.
<cw-popover>
  <cw-button slot="trigger">Toggle</cw-button>
  This is a popover.
</cw-popover>
import CwButton from '@cordwainer/cw-elements/dist/react/button';
import CwPopover from '@cordwainer/cw-elements/dist/react/popover';

const App = () => (
  <CwPopover>
    <CwButton slot="trigger">Toggle</CwButton>
    This is a popover.
  </CwPopover>
);

Examples

Placement

The preferred placement of the popover can be set with the placement attribute. Note that the actual position may vary to ensure the popover remains in the viewport.

Toggle This is a popover.
<cw-popover placement="top-start">
  <cw-button slot="trigger">Toggle</cw-button>
  This is a popover.
</cw-popover>
import CwButton from '@cordwainer/cw-elements/dist/react/button';
import CwPopover from '@cordwainer/cw-elements/dist/react/popover';

const App = () => (
  <CwPopover placement="top-start">
    <CwButton slot="trigger">Toggle</CwButton>
    This is a popover.
  </CwPopover>
);

Distance and Skidding

The distance from the panel to the trigger, and its offset along the trigger, can be customized with the distance and skidding attributes, respectively. Both are specified in pixels.

Toggle This is a popover.
<cw-popover distance="20" skidding="20">
  <cw-button slot="trigger">Toggle</cw-button>
  This is a popover.
</cw-popover>
import CwButton from '@cordwainer/cw-elements/dist/react/button';
import CwPopover from '@cordwainer/cw-elements/dist/react/popover';

const App = () => (
  <CwPopover distance={20} skidding={20}>
    <CwButton slot="trigger">Toggle</CwButton>
    This is a popover.
  </CwPopover>
);

Arrow

Add the arrow attribute to display an arrow pointing at the trigger. Its size and color can be customized with the --arrow-size and --arrow-color custom properties, or via ::part(arrow).

Toggle This is a popover.
<cw-popover arrow>
  <cw-button slot="trigger">Toggle</cw-button>
  This is a popover.
</cw-popover>
import CwButton from '@cordwainer/cw-elements/dist/react/button';
import CwPopover from '@cordwainer/cw-elements/dist/react/popover';

const App = () => (
  <CwPopover arrow>
    <CwButton slot="trigger">Toggle</CwButton>
    This is a popover.
  </CwPopover>
);

Disabled

Add the disabled attribute to prevent the popover from opening.

Toggle This is a popover.
<cw-popover disabled>
  <cw-button slot="trigger">Toggle</cw-button>
  This is a popover.
</cw-popover>
import CwButton from '@cordwainer/cw-elements/dist/react/button';
import CwPopover from '@cordwainer/cw-elements/dist/react/popover';

const App = () => (
  <CwPopover disabled>
    <CwButton slot="trigger">Toggle</CwButton>
    This is a popover.
  </CwPopover>
);

Controlling Open State

Use the open attribute, or the show() and hide() methods, to control the popover’s open state from JavaScript.

Toggle This is a popover.
<cw-popover class="popover-manual">
  <cw-button slot="trigger">Toggle</cw-button>
  This is a popover.
</cw-popover>

<script>
  const popover = document.querySelector('.popover-manual');
  popover.addEventListener('cw-after-show', () => console.log('shown'));
  popover.addEventListener('cw-after-hide', () => console.log('hidden'));
</script>
import CwButton from '@cordwainer/cw-elements/dist/react/button';
import CwPopover from '@cordwainer/cw-elements/dist/react/popover';

const App = () => (
  <CwPopover onCwAfterShow={() => console.log('shown')} onCwAfterHide={() => console.log('hidden')}>
    <CwButton slot="trigger">Toggle</CwButton>
    This is a popover.
  </CwPopover>
);

Importing

If you’re using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use any of the following snippets to cherry pick this component.

Script Import Bundler React

To import this component from the CDN using a script tag:

<script type="module" src="https://cdn.jsdelivr.net/npm/@cordwainer/cw-elements@1.5.2/cdn/components/popover/popover.js"></script>

To import this component from the CDN using a JavaScript import:

import 'https://cdn.jsdelivr.net/npm/@cordwainer/cw-elements@1.5.2/cdn/components/popover/popover.js';

To import this component using a bundler:

import '@cordwainer/cw-elements/dist/components/popover/popover.js';

To import this component as a React component:

import CwPopover from '@cordwainer/cw-elements/dist/react/popover';

Slots

Name Description
(default) The popover’s content.
trigger The element that anchors and toggles the popover, usually a <cw-button>.

Learn more about using slots.

Properties

Name Description Reflects Type Default
open Indicates whether or not the popover is open. You can toggle this attribute to show and hide the popover, or you can use the show() and hide() methods. Clicking outside the popover or pressing Escape closes it too. boolean false
placement The preferred placement of the popover. Note that the actual placement may vary as needed to keep the popover inside of the viewport. 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'right' | 'right-start' | 'right-end' | 'left' | 'left-start' | 'left-end' 'top'
disabled Disables the popover so it can’t be opened. boolean false
distance The distance in pixels from which to offset the popover away from its trigger. number 0
skidding The distance in pixels from which to offset the popover along its trigger. number 0
arrow Attaches an arrow to the popover, pointing at the trigger. The arrow’s size and color can be customized using the --arrow-size and --arrow-color custom properties, or via ::part(arrow). boolean false
updateComplete A read-only promise that resolves when the component has finished updating.

Learn more about attributes and properties.

Events

Name React Event Description Event Detail
cw-show onCwShow Emitted when the popover opens. -
cw-after-show onCwAfterShow Emitted after the popover opens and all animations are complete. -
cw-hide onCwHide Emitted when the popover closes, whether via hide()/toggling open, or dismissed natively (clicking outside, pressing Escape). -
cw-after-hide onCwAfterHide Emitted after the popover closes and all animations are complete. -

Learn more about events.

Methods

Name Description Arguments
show() Shows the popover. -
hide() Hides the popover. -
reposition() Instructs the popover to recalculate and update its position. Useful if the trigger’s size or position changes. -

Learn more about methods.

Custom Properties

Name Description Default
--arrow-size The size of the arrow. Note that an arrow won’t be shown unless the arrow attribute is used. 6px
--arrow-color The color of the arrow. var(–cw-color-neutral-0)

Learn more about customizing CSS custom properties.

Parts

Name Description
trigger The container that wraps the trigger.
popup The outer popup container, the element the native Popover API and floating-ui both act on. Has no visible styling of its own — see body for the visible box.
body The popup’s visible box (background, border, padding) wrapping its content.
arrow The arrow’s container, present only when the arrow attribute is set.

Learn more about customizing CSS parts.

Animations

Name Description
popover.show The animation to use when showing the popover.
popover.hide The animation to use when hiding the popover.

Learn more about customizing animations.