Popover
A non-modal dialog, that displays rich content in a portal, triggered by a clickable element.
# Features
- Trigger and popover are automatically associated semantically using ARIA for improved accessibility.
- Popover can be closed by interacting outside of it or pressing the
Escape
key. - Focus is moved and contained within the popover while it is open, and returned to the trigger element when it is closed.
- Customization options for side, alignment, offsets, and collision handling.
# Dependencies
This module depends on focus-trap and @floating-ui/dom.
# Anatomy
Typically, a popover consists of:
- Trigger: The element that triggers the popover.
- Popover: The overlay, which is positioned relative to the trigger, and may contain
- Close Button: An optional element to close the popover.
- Arrow: An optional element that points to the trigger.
<script>
import { createPopover } from '@grail-ui/svelte';
const { usePopoverTrigger, triggerAttrs, usePopover, popoverAttrs, closeButtonAttrs, open } = createPopover();
</script>
<button use:usePopoverTrigger {...$triggerAttrs}>Click</button>
{#if $open}
<section use:usePopover {...$popoverAttrs}>
<div>
Content
</div>
<button {...$closeButtonAttrs}>Close</button>
</section>
{/if}
# Examples
# Changing placement
To change the placement of the popover relatively to the trigger, set the positioning
property.
createPopover({
positioning: {
placement: "top-start",
gutter: 10
},
})
# Custom portal container
If you want to customize the element that your popover portals into, use the portal
and
pass the actual element or a CSS selector.
createPopover({
positioning: {
placement: "top-start",
},
portal: '#custom',
})
# Accessibility
# Keyboard Interactions
Key | description |
---|---|
Esc
|
Closes the popover and moves focus to trigger element. |
Tab
|
Moves focus to the next focusable element. |
Shift
+
Tab
|
Moves focus to the previous focusable element. |
# API
# PopoverConfig
Property | Description | Default |
---|---|---|
open? |
boolean The open state of the popover when it is initially rendered. |
false |
positioning? |
Partial<PositioningOptions> Where to place the floating element relative to its reference element. |
— |
portal? |
string | HTMLElement | null Where to "portal" the floating element outside it's initial DOM position.
It can be a HTMLElement or a CSS selector that points to an already existing element. |
"body" |
onOpenChange? |
(value?: boolean) => void | undefined Event handler called when the open state of the tooltip changes. |
— |
# PopoverReturn
Property | Description |
---|---|
usePopoverTrigger |
Action<HTMLElement, void> Action for the trigger element. |
triggerAttrs |
Readable<Record<string, string | undefined>> HTML attributes for the trigger element. |
usePopover |
Action<HTMLElement, void> Action for the popover element. |
popoverAttrs |
Readable<Record<string, string>> HTML attributes for the popover element. |
closeButtonAttrs |
Readable<Record<string, string>> HTML attributes for the popover element. |
arrowAttrs |
Readable<Record<string, string>> HTML attributes for the popover arrow element. |
open |
Writable<boolean> The controlled open state of the popover. |
referenceEl |
Writable<HTMLElement | undefined> The element to which the popover should be attached.
Defaults to the usePopoverTrigger . |
# PositioningOptions
Property | Description | Default |
---|---|---|
strategy? |
absolute | fixed The strategy to use for positioning. |
"absolute" |
placement? |
top | top-start | top-end | right | right-start | right-end | bottom | bottom-start | bottom-end | left | left-start | left-end The initial placement of the floating element. |
"top" |
offset? |
Object The offset of the floating element. |
— |
gutter? |
number The main axis offset or gap between the reference and floating elements. |
5 |
overflowPadding? |
number The virtual padding around the viewport edges to check for overflow. |
8 |
flip? |
boolean Whether to flip the placement. |
true |
overlap? |
boolean Whether the floating element can overlap the reference element. |
false |
sameWidth? |
boolean Whether to make the floating element same width as the reference element. |
false |
fitViewport? |
boolean Whether the floating element should fit the viewport. |
false |
boundary? |
@floating-ui/dom.Boundary The overflow boundary of the reference element. |
— |