![Swetha Gopalakrishnan](https://web.dev/images/authors/swethagopalakrishnan.jpg) Swetha Gopalakrishnan [X](https://twitter.com/swetha_go) [LinkedIn](https://www.linkedin.com/in/swetha-gopalakrishnan-5ba92936) ![Saurabh Rajpal](https://web.dev/images/authors/saurabhrajpal.jpg) Saurabh Rajpal [X](https://twitter.com/imsaurabhrajpal) [LinkedIn](https://www.linkedin.com/in/imsaurabhrajpal)

<br />

Popovers are everywhere on the web. You can see them in menus, toggletips, and
dialogs, used for features such as account settings, disclosure widgets, and
product card previews. Despite how prevalent these components are, building them
in browsers is still surprisingly cumbersome. To resolve this, a new set of
declarative HTML APIs for building popovers are coming to browsers, the first of
these being the [Popover API](https://developer.mozilla.org/docs/Web/API/Popover_API).

<iframe src="https:///frame/blog/css-ui-ecommerce-popover/index_76d3d94ec159048016d62789a639cca432cc7f10dc84f5e68e01d2f0b49280a9.frame" class="framebox inherit-locale " allow="clipboard-write https://" allowfullscreen is-upgraded></iframe>

> [!NOTE]
> **Note:** To learn how to implement the Popover API in your own site, read [Introducing the popover API](https://developer.chrome.com/blog/introducing-popover-api.md.txt) by Una Kravets.

A popover is commonly confused with a dialog. However there are some key
differences in their behavior. A `dialog` element opened with `dialog.showModal`
(a modal dialog), is an experience which requires explicit user interaction to
close the modal. A `popover` supports light-dismiss. A modal `dialog` does not.
A modal dialog makes the rest of the page inert. A `popover` does not.
[Read more about the differences](https://hidde.blog/dialog-modal-popover-differences/).

> [!IMPORTANT]
> **Key Term:** light-dismiss refers to the closing of a popover element when you click outside of its bounding box

This article is [is part of a series](https://developer.chrome.com/blog/css-ui-ecommerce.md.txt) which discusses how ecommerce companies
enhanced their website using new CSS and UI features. In this article, discover
how Tokopedia implemented and benefited from the Popover API.

## Tokopedia

> Using popover attributes reduced up to 70% lines of code in React. The modal
> can be natively controlled by HTML instead of requiring event handling in
> JavaScript and using `React.createPortal` for moving the modal DOM to the end of
> `document.body`. We are also able to use `@starting-style` to animate the
> opening and closing of the popover.---[Andy
> Wihalim](https://www.linkedin.com/in/andy-wihalim-a4872512b), Senior Software Engineer, Tokopedia.

Tokopedia's Product Detail Pages (PDP) contain multiple product images for each
product. When the product thumbnail is clicked, a modal is opened to show the
enlarged image. This is a common pattern used in ecommerce websites.

### Code

Tokopedia uses React for their frontend development. Before implementing the
popover API for this modal, they used a DOM modal and a button. The button
changed the React state to open the modal. With the popover API, they specify a
`popovertarget` attribute in the element which opens the popover with a value
that is the same as the ID of the popover element.

With this basic implementation, the popover works but appears and disappears
without any animation. To create a smooth entry and exit animation for the
popover, use `:popover-open` and `@starting-style` and allow animation of
discrete properties.
In the following code example, the popover scales in and out using the
`transform: 'scale()'`property.

This [code example](https://codepen.io/web-dot-dev/pen/OJBoLNb) shows
how to implement entry and exit animations for the popover API.

```html
<Thumbnail popovertarget="medialightbox" />
<MediaLightbox popover id="medialightbox" />
```

```javascript
export const cssModalWrapper = css({
  background: NN0,
  border: 'none',
  borderRadius: '.625rem',
  width: 1024,
  padding: 24,

  '&::backdrop': {
    opacity: 0,
    transitionProperty: 'opacity, display',
    transition: '.25s ease-out',
    transitionBehavior: 'allow-discrete',
  },

  transitionProperty: 'transform, opacity, display',
  transition: '.25s ease-out',
  transitionBehavior: 'allow-discrete',

  transform: 'scale(0.8)',
  opacity: 0,
  '@starting-style': {
    transform: 'scale(1)',
    opacity: 1,
  },

  '&:popover-open': {
    transform: 'scale(1)',
    opacity: 1,
    '@starting-style': {
      transform: 'scale(0.8)',
      opacity: 0,
    },
  },
});
```

To cater to browsers that don't support the popover API, Tokopedia implemented
the [popover-polyfill](https://github.com/oddbird/popover-polyfill) by oddbird,
which is only 3.2 KB with gzip compression. They were satisfied with the polyfill
as it worked well and did not cause performance regressions. Overall, they were
able to reduce up to 70% lines of code in React with the popover API.

## Things to consider when using the Popover API

Tokopedia uses React, and the team achieved code splitting by unmounting the
popover component for pages which don't use it, then doing a code split for the
popover content. This way, they reduced the size of their initial request.

Consider combining popovers with CSS anchor positioning
([coming soon to Chrome](https://chromestatus.com/feature/5124922471874560))
to position them relative to other elements. This is helpful for menus and tooltips for example.

## Resources

- [Introducing the popover API](https://developer.chrome.com/blog/introducing-popover-api.md.txt)
- [The difference between a popover and a dialog](https://developer.chrome.com/blog/introducing-popover-api.md.txt#the_difference_between_a_popover_and_a_dialog)
- Do you want to report a bug or request a new feature? [We want to hear from you](https://issues.chromium.org/issues/new?component=1456565&template=0).

Explore the other articles in this series that talk about how ecommerce
companies benefited from using new CSS and UI features such as Scroll-driven
animations, popover, container queries and the `has()` selector.

- [Why do Web UI Capabilities matter for your ecommerce site?](https://developer.chrome.com/blog/css-ui-ecommerce.md.txt)
- [Scroll-driven animations case studies](https://developer.chrome.com/blog/css-ui-ecommerce-sda.md.txt)
- [View Transitions case studies](https://developer.chrome.com/blog/css-ui-ecommerce-vt.md.txt)
- [Container Queries case studies](https://developer.chrome.com/blog/css-ui-ecommerce-cq.md.txt)
- [:has() selector case studies](https://developer.chrome.com/blog/css-ui-ecommerce-has.md.txt)

> [!NOTE]
> **Note:** This post was updated on 2024-09-13 to use the correct order for nested `@starting-style` rules. As of Chrome 130, `@starting-style` rules must be placed after the post-entry state (normal) declarations.