A really simple and minimalistic popover component for your apps.
IMPORTANT:
- You may add
width: max-content
to the content element by yourself to avoid layout interference as it described here.
- Minimalistic - no wrapper DOM nodes!
- Popover API support
- Full control over position
- Works with SSR and Astro
- Multiple trigger events with vue-style modifiers
- Custom anchor element
No extra DOM nodes. Trigger node will have data-popover-open
attribute, so you can use it in your CSS styles.
<button id="trigger-element">Toggle popover!</button>
<Popover triggerElement="#trigger-element">
<div>Nice content here</div>
</Popover>
This component uses Popover API by default.
Don't forget to reset default browser styles for [popover]
:
[popover] {
margin: 0;
background-color: transparent;
padding: 0;
border: none;
}
You can pass all the options for positioning. See docs for computePosition.
import { flip } from "@floating-ui/dom";
<button id="trigger-element">Toggle popover!</button>
<Popover
triggerElement="#trigger-element"
// Full control over position
autoUpdate
computePositionOptions={{ placement: "bottom-start", middleware: [flip()] }}
>
<div>I'm a content</div>
</Popover>;
You can pass multiple trigger events with modifiers:
Events support the following modifiers:
capture
once
prevent
stop
passive
<button id="trigger-element">Toggle popover!</button>
<Popover
triggerElement="#trigger-element"
triggerEvents="click.capture|pointerdown"
>
<div>I'm a content</div>
</Popover>
Sometimes it's necessary the anchor element to be different from trigger element. You may pass optional selector to find anchor element:
<div id="anchor-element"></div>
<button id="trigger-element">Toggle popover!</button>
<Popover
triggerElement="#trigger-element"
// Here you can pass CSS selector or HTML element
anchorElement="#anchor-element"
>
<div>
<button autofocus>hi</button>
This div is visible when popover is open!
</div>
</Popover>
This package has the following peer dependencies:
"@floating-ui/dom": "^1.5",
"solid-js": "^1.8"
so you need to install required packages by yourself.
pnpm i solid-js @floating-ui/dom solid-simple-popover
import { Popover } from "solid-simple-popover";
import { flip } from "@floating-ui/dom";
<button id="trigger-button">Toggle popover</button>
<Popover
triggerElement="trigger-button"
// Full control over position
autoUpdate
computePositionOptions={{ placement: "bottom-start", middleware: [flip()] }}
// Highly customizable
sameWidth
dataAttributeName="data-open"
// You may pass custom selector here
anchorElement="#trigger-button"
// Astro support
contentElementSelector="div"
>
<div>This div is visible when popover is open!</div>
</Popover>;
import { type ComputePositionConfig, type AutoUpdateOptions, type ComputePositionReturn } from "@floating-ui/dom";
import { type JSXElement, type ParentComponent } from "solid-js";
export type PopoverProps = {
/**
* HTML Element or CSS selector to find trigger element which triggers popover
*/
triggerElement?: JSXElement;
/**
* HTML element or CSS selector to find anchor element which is used for positioning
* Can be used with Astro, because astro wraps trigger element into astro-slot
* and position breaks
*/
anchorElement?: string | HTMLElement;
open?: boolean;
defaultOpen?: boolean;
/**
* Disables listening to trigger events
* Note: if your trigger element has `disabled` state (like button or input), popover also won't be triggered
*/
disabled?: boolean;
/** Should content have the same width as trigger */
sameWidth?: boolean;
/** Options for floating-ui computePosition function */
computePositionOptions?: ComputePositionConfig;
/**
* @default "pointerdown"
* If set to null no event would trigger popover,
* so you need to trigger it mannually.
* Event name or list of event names separated by "|" which triggers popover.
* You may also add modifiers like "capture", "passive", "once", "prevent", "stop" to the event separated by ".":
* @example "pointerdown.capture.once.prevent|click"
*/
triggerEvents?: string | null;
/**
* Close popover on interaction outside
* @default true
* By default when popover is open it will listen to "pointerdown" event outside of popover content and trigger
*/
closeOnOutsideInteraction?: boolean;
/**
* Data attribute name to set on trigger element
* @default "data-popover-open"
*/
dataAttributeName?: string;
/**
* CSS selector to find html element inside content
* Can be used with Astro, because astro wraps element into astro-slot
* and position breaks
*/
contentElementSelector?: string;
/**
* autoUpdate option for floating ui
* @see https://floating-ui.com/docs/autoupdate
*/
autoUpdate?: boolean;
/**
* Applies only if autoUpdate is true
* @see https://floating-ui.com/docs/autoupdate#options
*/
autoUpdateOptions?: AutoUpdateOptions;
/**
* Close popover on escape key press.
* Uses 'keydown' event with 'Escape' key.
* @default true
*/
closeOnEscape?: boolean;
onOpenChange?: (open: boolean) => void;
onComputePosition?: (data: ComputePositionReturn) => void;
};
export declare const Popover: ParentComponent<PopoverProps>;
MIT