406 lines
13 KiB
Markdown
406 lines
13 KiB
Markdown
# Popover
|
|
|
|
A popover positioned relative to an anchor element.
|
|
|
|
## Import
|
|
|
|
```
|
|
Copyts
|
|
import { Popover } from "@kobalte/core/popover";
|
|
// or
|
|
import { Root, Trigger, ... } from "@kobalte/core/popover";
|
|
// or (deprecated)
|
|
import { Popover } from "@kobalte/core";
|
|
```
|
|
|
|
```
|
|
Copyts
|
|
import { Popover } from "@kobalte/core/popover";
|
|
// or
|
|
import { Root, Trigger, ... } from "@kobalte/core/popover";
|
|
// or (deprecated)
|
|
import { Popover } from "@kobalte/core";
|
|
```
|
|
|
|
## Features
|
|
|
|
- Follow the [WAI ARIA Popover](https://www.w3.org/WAI/ARIA/apg/patterns/popovermodal/) design pattern.
|
|
- Supports modal and non-modal modes.
|
|
- Provides screen reader announcements via rendered title and description.
|
|
- Focus is fully managed and customizable.
|
|
- Optionally render a pointing arrow.
|
|
- Can be controlled or uncontrolled.
|
|
|
|
## Anatomy
|
|
|
|
The popover consists of:
|
|
|
|
- **Popover:** The root container for a popover.
|
|
- **Popover.Trigger:** The button that opens the popover.
|
|
- **Popover.Anchor:** An optional element to position the `Popover.Content` against.
|
|
- **Popover.Portal:** Portals its children into the `body` when the popover is open.
|
|
- **Popover.Content:** Contains the content to be rendered when the popover is open.
|
|
- **Popover.Arrow:** An optional arrow element to render alongside the popover.
|
|
- **Popover.CloseButton:** The button that closes the popover.
|
|
- **Popover.Title:** An accessible title to be announced when the popover is open.
|
|
- **Popover.Description:** An optional accessible description to be announced when the popover is open.
|
|
|
|
```
|
|
Copytsx
|
|
<Popover>
|
|
<Popover.Trigger />
|
|
<Popover.Anchor />
|
|
<Popover.Portal>
|
|
<Popover.Content>
|
|
<Popover.Arrow />
|
|
<Popover.CloseButton />
|
|
<Popover.Title />
|
|
<Popover.Description />
|
|
</Popover.Content>
|
|
</Popover.Portal>
|
|
</Popover>
|
|
```
|
|
|
|
```
|
|
Copytsx
|
|
<Popover>
|
|
<Popover.Trigger />
|
|
<Popover.Anchor />
|
|
<Popover.Portal>
|
|
<Popover.Content>
|
|
<Popover.Arrow />
|
|
<Popover.CloseButton />
|
|
<Popover.Title />
|
|
<Popover.Description />
|
|
</Popover.Content>
|
|
</Popover.Portal>
|
|
</Popover>
|
|
```
|
|
|
|
## Example
|
|
|
|
Open
|
|
|
|
index.tsxstyle.css
|
|
|
|
```
|
|
Copytsx
|
|
import { Popover } from "@kobalte/core/popover";
|
|
import { CrossIcon } from "some-icon-library";
|
|
import "./style.css";
|
|
|
|
function App() {
|
|
return (
|
|
<Popover>
|
|
<Popover.Trigger class="popover__trigger">Open</Popover.Trigger>
|
|
<Popover.Portal>
|
|
<Popover.Content class="popover__content">
|
|
<Popover.Arrow />
|
|
<div class="popover__header">
|
|
<Popover.Title class="popover__title">About Kobalte</Popover.Title>
|
|
<Popover.CloseButton class="popover__close-button">
|
|
<CrossIcon />
|
|
</Popover.CloseButton>
|
|
</div>
|
|
<Popover.Description class="popover__description">
|
|
A UI toolkit for building accessible web apps and design systems with SolidJS.
|
|
</Popover.Description>
|
|
</Popover.Content>
|
|
</Popover.Portal>
|
|
</Popover>
|
|
);
|
|
}
|
|
```
|
|
|
|
```
|
|
Copytsx
|
|
import { Popover } from "@kobalte/core/popover";
|
|
import { CrossIcon } from "some-icon-library";
|
|
import "./style.css";
|
|
|
|
function App() {
|
|
return (
|
|
<Popover>
|
|
<Popover.Trigger class="popover__trigger">Open</Popover.Trigger>
|
|
<Popover.Portal>
|
|
<Popover.Content class="popover__content">
|
|
<Popover.Arrow />
|
|
<div class="popover__header">
|
|
<Popover.Title class="popover__title">About Kobalte</Popover.Title>
|
|
<Popover.CloseButton class="popover__close-button">
|
|
<CrossIcon />
|
|
</Popover.CloseButton>
|
|
</div>
|
|
<Popover.Description class="popover__description">
|
|
A UI toolkit for building accessible web apps and design systems with SolidJS.
|
|
</Popover.Description>
|
|
</Popover.Content>
|
|
</Popover.Portal>
|
|
</Popover>
|
|
);
|
|
}
|
|
```
|
|
|
|
## Usage
|
|
|
|
### Default open
|
|
|
|
An initial, uncontrolled open value can be provided using the `defaultOpen` prop.
|
|
|
|
```
|
|
Copytsx
|
|
<Popover defaultOpen>...</Popover>
|
|
```
|
|
|
|
```
|
|
Copytsx
|
|
<Popover defaultOpen>...</Popover>
|
|
```
|
|
|
|
### Controlled open
|
|
|
|
The `open` prop can be used to make the open state controlled. The `onOpenChange` event is fired when the user presses the trigger, close button or interact outside, and receives the new value.
|
|
|
|
Open
|
|
|
|
```
|
|
Copytsx
|
|
import { createSignal } from "solid-js";
|
|
|
|
function ControlledExample() {
|
|
const [open, setOpen] = createSignal(false);
|
|
|
|
return (
|
|
<Popover open={open()} onOpenChange={setOpen}>
|
|
<Popover.Trigger>{open() ? "Close" : "Open"}</Popover.Trigger>
|
|
<Popover.Portal>
|
|
<Popover.Content>...</Popover.Content>
|
|
</Popover.Portal>
|
|
</Popover>
|
|
);
|
|
}
|
|
```
|
|
|
|
```
|
|
Copytsx
|
|
import { createSignal } from "solid-js";
|
|
|
|
function ControlledExample() {
|
|
const [open, setOpen] = createSignal(false);
|
|
|
|
return (
|
|
<Popover open={open()} onOpenChange={setOpen}>
|
|
<Popover.Trigger>{open() ? "Close" : "Open"}</Popover.Trigger>
|
|
<Popover.Portal>
|
|
<Popover.Content>...</Popover.Content>
|
|
</Popover.Portal>
|
|
</Popover>
|
|
);
|
|
}
|
|
```
|
|
|
|
### With custom anchor
|
|
|
|
Use the `Popover.Anchor` component to anchor the content to another element if you do not want to use the trigger as the anchor.
|
|
|
|
The popover opens when you click here.
|
|
|
|
But it's anchored to the whole div.
|
|
|
|
```
|
|
Copytsx
|
|
<Popover>
|
|
<Popover.Anchor>
|
|
<p>
|
|
The popover opens when you click <Popover.Trigger>here</Popover.Trigger>.
|
|
</p>
|
|
<p>But it's anchored to the whole div.</p>
|
|
</Popover.Anchor>
|
|
<Popover.Portal>
|
|
<Popover.Content>...</Popover.Content>
|
|
</Popover.Portal>
|
|
</Popover>
|
|
```
|
|
|
|
```
|
|
Copytsx
|
|
<Popover>
|
|
<Popover.Anchor>
|
|
<p>
|
|
The popover opens when you click <Popover.Trigger>here</Popover.Trigger>.
|
|
</p>
|
|
<p>But it's anchored to the whole div.</p>
|
|
</Popover.Anchor>
|
|
<Popover.Portal>
|
|
<Popover.Content>...</Popover.Content>
|
|
</Popover.Portal>
|
|
</Popover>
|
|
```
|
|
|
|
### Origin-aware animations
|
|
|
|
We expose a CSS custom property `--kb-popover-content-transform-origin` which can be used to animate the content from its computed origin.
|
|
|
|
```
|
|
Copycss
|
|
/* style.css */
|
|
.popover__content {
|
|
transform-origin: var(--kb-popover-content-transform-origin);
|
|
animation: contentHide 250ms ease-in forwards;
|
|
}
|
|
|
|
.popover__content[data-expanded] {
|
|
animation: contentShow 250ms ease-out;
|
|
}
|
|
|
|
@keyframes contentShow {
|
|
from {
|
|
opacity: 0;
|
|
transform: scale(0.96);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
|
|
@keyframes contentHide {
|
|
from {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
}
|
|
to {
|
|
opacity: 0;
|
|
transform: scale(0.96);
|
|
}
|
|
}
|
|
```
|
|
|
|
```
|
|
Copycss
|
|
/* style.css */
|
|
.popover__content {
|
|
transform-origin: var(--kb-popover-content-transform-origin);
|
|
animation: contentHide 250ms ease-in forwards;
|
|
}
|
|
|
|
.popover__content[data-expanded] {
|
|
animation: contentShow 250ms ease-out;
|
|
}
|
|
|
|
@keyframes contentShow {
|
|
from {
|
|
opacity: 0;
|
|
transform: scale(0.96);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
|
|
@keyframes contentHide {
|
|
from {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
}
|
|
to {
|
|
opacity: 0;
|
|
transform: scale(0.96);
|
|
}
|
|
}
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### Popover
|
|
|
|
`Popover` is equivalent to the `Root` import from `@kobalte/core/popover` (and deprecated `Popover.Root`).
|
|
|
|
| Prop | Description |
|
|
| --- | --- |
|
|
| open | `boolean`<br> The controlled open state of the popover. |
|
|
| defaultOpen | `boolean`<br> The default open state when initially rendered. Useful when you do not need to control the open state. |
|
|
| onOpenChange | `(open: boolean) => void`<br> Event handler called when the open state of the popover changes. |
|
|
| id | `string`<br> A unique identifier for the component. The id is used to generate id attributes for nested components. If no id prop is provided, a generated id will be used. |
|
|
| modal | `boolean`<br> Whether the popover should be the only visible content for screen readers, when set to `true`: <br> \- interaction with outside elements will be disabled. <br> \- scroll will be locked. <br> \- focus will be locked inside the popover content. <br> \- elements outside the popover content will not be visible for screen readers. |
|
|
| preventScroll | `boolean`<br> Whether the scroll should be locked even if the popover is not modal. |
|
|
| forceMount | `boolean`<br> Used to force mounting the popover (portal and content) when more control is needed. Useful when controlling animation with SolidJS animation libraries. |
|
|
| translations | [`PopoverIntlTranslations`](https://github.com/kobaltedev/kobalte/blob/main/packages/core/src/popover/popover.intl.ts)<br> Localization strings. |
|
|
|
|
`Popover` also accepts the following props to customize the placement of the `Popover.Content`.
|
|
|
|
| Prop | Description |
|
|
| --- | --- |
|
|
| getAnchorRect | `(anchor?: HTMLElement) => AnchorRect | undefined`<br> Function that returns the anchor element's DOMRect. |
|
|
| anchorRef | `Accessor<HTMLElement | undefined>`<br> A ref for the anchor element. Useful if you want to use an element outside `Popover` as the popover anchor. |
|
|
| placement | `Placement`<br> The placement of the popover. |
|
|
| gutter | `number`<br> The distance between the popover and the trigger/anchor element. By default, it's 0 plus half of the arrow offset, if it exists. |
|
|
| shift | `number`<br> The skidding of the popover along the anchor element. |
|
|
| flip | `boolean | string`<br> Controls the behavior of the popover when it overflows the viewport:<br> \- If a `boolean`, specifies whether the popover should flip to the opposite side when it overflows.<br> \- If a `string`, indicates the preferred fallback placements when it overflows.<br>The placements must be spaced-delimited, e.g. "top left". |
|
|
| slide | `boolean`<br> Whether the popover should slide when it overflows. |
|
|
| overlap | `boolean`<br> Whether the popover can overlap the anchor element when it overflows. |
|
|
| sameWidth | `boolean`<br> Whether the popover should have the same width as the anchor element. This will be exposed to CSS as `--kb-popper-anchor-width`. |
|
|
| fitViewport | `boolean`<br> Whether the popover should fit the viewport. If this is set to true, the popover content will have `maxWidth` and `maxHeight` set to the viewport size. This will be exposed to CSS as `--kb-popper-available-width` and `--kb-popper-available-height`. |
|
|
| hideWhenDetached | `boolean`<br> Whether to hide the popover when the anchor element becomes occluded. |
|
|
| detachedPadding | `number`<br> The minimum padding in order to consider the anchor element occluded. |
|
|
| arrowPadding | `number`<br> The minimum padding between the arrow and the popover corner. |
|
|
| overflowPadding | `number`<br> The minimum padding between the popover and the viewport edge. This will be exposed to CSS as `--kb-popper-overflow-padding`. |
|
|
|
|
### Popover.Trigger
|
|
|
|
`Popover.Trigger` consists of [Button](https://kobalte.dev/docs/core/components/button).
|
|
|
|
| Data attribute | Description |
|
|
| --- | --- |
|
|
| data-expanded | Present when the popover is open. |
|
|
| data-closed | Present when the popover is close. |
|
|
|
|
`Popover.Anchor` , `Popover.Content` , `Popover.Arrow`, `Popover.Title`, `Popover.Description` and `Popover.CloseButton` share the same data-attributes.
|
|
|
|
### Popover.Content
|
|
|
|
The popper positioner will copy the same `z-index` as the `Popover.Content`.
|
|
|
|
| Prop | Description |
|
|
| --- | --- |
|
|
| onOpenAutoFocus | `(event: Event) => void`<br> Event handler called when focus moves into the component after opening. It can be prevented by calling `event.preventDefault`. |
|
|
| onCloseAutoFocus | `(event: Event) => void`<br> Event handler called when focus moves to the trigger after closing. It can be prevented by calling `event.preventDefault`. |
|
|
| onEscapeKeyDown | `(event: KeyboardEvent) => void`<br> Event handler called when the escape key is down. It can be prevented by calling `event.preventDefault`. |
|
|
| onPointerDownOutside | `(event: PointerDownOutsideEvent) => void`<br> Event handler called when a pointer event occurs outside the bounds of the component. It can be prevented by calling `event.preventDefault`. |
|
|
| onFocusOutside | `(event: FocusOutsideEvent) => void`<br> Event handler called when the focus moves outside the bounds of the component. It can be prevented by calling `event.preventDefault`. |
|
|
| onInteractOutside | `(event: InteractOutsideEvent) => void`<br> Event handler called when an interaction (pointer or focus event) happens outside the bounds of the component. It can be prevented by calling `event.preventDefault`. |
|
|
|
|
### Popover.Arrow
|
|
|
|
| Prop | Description |
|
|
| --- | --- |
|
|
| size | `number`<br> The size of the arrow. |
|
|
|
|
## Rendered elements
|
|
|
|
| Component | Default rendered element |
|
|
| --- | --- |
|
|
| `Popover` | none |
|
|
| `Popover.Trigger` | `button` |
|
|
| `Popover.Anchor` | `div` |
|
|
| `Popover.Portal` | `Portal` |
|
|
| `Popover.Content` | `div` |
|
|
| `Popover.Arrow` | `div` |
|
|
| `Popover.CloseButton` | `button` |
|
|
| `Popover.Title` | `h2` |
|
|
| `Popover.Description` | `p` |
|
|
|
|
## Accessibility
|
|
|
|
### Keyboard Interactions
|
|
|
|
| Key | Description |
|
|
| --- | --- |
|
|
| `Space` | When focus is on the trigger, opens/closes the popover. |
|
|
| `Enter` | When focus is on the trigger, opens/closes the popover. |
|
|
| `Tab` | Moves focus to the next focusable element. |
|
|
| `Shift` \+ `Tab` | Moves focus to the previous focusable element. |
|
|
| `Esc` | Closes the popover and moves focus to the trigger. |
|
|
|
|
Previous[←Pagination](https://kobalte.dev/docs/core/components/pagination)Next[Progress→](https://kobalte.dev/docs/core/components/progress) |