# Popover Attribute Polyfill
[](https://github.com/oddbird/popover-polyfill/actions/workflows/test.yml) [](https://badge.fury.io/js/@oddbird%2Fpopover-polyfill) [](https://app.netlify.com/sites/popover-polyfill/deploys)
- [Demo](https://popover.oddbird.net/)
- [Explainer](https://open-ui.org/components/popover.research.explainer/)
This polyfills the HTML `popover` attribute and
`showPopover`/`hidePopover`/`togglePopover` methods onto HTMLElement, as well as
the `popovertarget` and `popovertargetaction` attributes on Button elements.
## Polyfill Installation
### Download a copy
The simplest, recommended way to install the polyfill is to copy it into your
project.
Download `popover.js` (or `popover.min.js`) [from
unpkg.com](https://unpkg.com/browse/@oddbird/popover-polyfill/dist/) and add it
to the appropriate directory in your project. Then, include it where necessary
with a `
```
Or without [JavaScript modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules):
```html
```
Note that the JS will inject CSS styles into your document (or ShadowRoot).
### With npm
For more advanced configuration, you can install with
[npm](https://www.npmjs.com/):
```sh
npm install @oddbird/popover-polyfill
```
After installing, you’ll need to use appropriate tooling to use
`node_modules/@oddbird/popover-polyfill/dist/popover.js`.
For most tooling such as Vite, Webpack, and Parcel, that will look like this:
```js
import '@oddbird/popover-polyfill';
```
If you want to manually apply the polyfill, you can instead import the
`isSupported` and `apply` functions directly from
`node_modules/@oddbird/popover-polyfill/dist/popover-fn.js` file.
With most tooling:
```js
import { apply, isSupported } from '@oddbird/popover-polyfill/fn';
```
Or in CommonJS environments:
```js
const { apply, isSupported } = require('@oddbird/popover-polyfill/fn');
```
An `isPolyfilled` function is also available, to detect if the Popover methods
have been polyfilled:
```js
import { isPolyfilled } from '@oddbird/popover-polyfill/fn';
```
### Via CDN
For prototyping or testing, you can use the npm package via a Content Delivery
Network. Avoid using JavaScript CDNs in production, for [many good
reasons](https://blog.wesleyac.com/posts/why-not-javascript-cdn) such as
performance and robustness.
```html
```
## Usage
After installation the polyfill will automatically add the correct methods and
attributes to the HTMLElement class.
## Caveats
This polyfill is not a perfect replacement for the native behavior; there are
some caveats which will need accommodations:
- A native `popover` has a `:popover-open` pseudo selector when in the open
state. Pseudo selectors cannot be polyfilled within CSS, and so instead the
polyfill will add the `.\:popover-open` CSS class to any open popover. In
other words a popover in the open state will have `class=":popover-open"`. In
CSS the `:` character must be escaped with a backslash.
- The `:popover-open` selector within JavaScript methods has been polyfilled,
so both `.querySelector(':popover-open')` _and_
`.querySelector('.\:popover-open')` will work to select the same element.
`matches` and `closest` have also been patched, so
`.matches(':popover-open')` will work the same as
`.matches('.\:popover-open')`.
- Using native `:popover-open` in CSS that does not support native `popover`
results in an invalid selector, and so the entire declaration is thrown
away. This is important because if you intend to style a popover using
`.\:popover-open` it will need to be a separate declaration. For example,
`[popover]:popover-open, [popover].\:popover-open` will not work.
- Native `popover` elements use the `:top-layer` pseudo element which gets
placed above all other elements on the page, regardless of overflow or
z-index. This is not possible to polyfill, and so this library simply sets a
really high `z-index`. This means if a popover is within an element that has
`overflow:` or `position:` CSS, then there will be visual differences between
the polyfill and the native behavior.
- Native _invokers_ (that is, buttons or inputs using the `popovertarget`
attribute) on `popover=auto` will render in the accessibility tree as elements
with `expanded`. The only way to do this in the polyfill is setting the
`aria-expanded` attribute on those elements. This _may_ impact mutation
observers or frameworks which do DOM diffing, or it may interfere with other
code which sets `aria-expanded` on elements.
- The polyfill uses `adoptedStyleSheets` to inject CSS onto the page (and each
Shadow DOM). If it can't use that it'll generate a `