pota/use/clickoutsidepota/use/clickoutside dismisses things when interaction moves away:
clickOutside fires when a pointer event lands outside an element,
and escape fires when the user presses
Escape — handy for menus, popovers, and dialogs. Both are ref
factories: attach them with use:ref.
clickOutside(handler, options?) — ref factory firing on a
pointerdown outside the element (documented below)escape(handler) — ref factory firing
on the Escape keyclickOutside(handler, options?)
| Argument | Type | Description |
|---|---|---|
handler |
(e: PointerEvent, node: Element) => void |
Called when a pointerdown lands outside the node. |
options.once |
boolean |
When true, detach after the first pointerdown. |
Returns: a ref function (node: Element) => void for use:ref.
The handler runs whenever a pointerdown lands outside the element
it's attached to. Cleanup is automatic: the listener is bound to the
element's reactive scope and detaches when the element unmounts.
import { render, signal } from 'pota'
import { Show } from 'pota/components'
import { clickOutside } from 'pota/use/clickoutside'
function App() {
const open = signal(false)
return (
<div>
<button on:click={() => open.write(true)}>open</button>
<Show when={open.read}>
<div use:ref={clickOutside(() => open.write(false))}>
<p>I close on outside click.</p>
</div>
</Show>
</div>
)
}
render(App)
clickOutside listens for pointerdown on document. "Outside"
means !node.contains(event.target) — DOM containment, not
component structure: clicks on DOM descendants don't fire, while
content portaled out of the node (a Portal
mounted elsewhere) counts as outside.{ once: true } maps to the native addEventListener once
option, so the document listener is removed after the first
pointerdown anywhere — including one inside the node, in which
case the handler never fires.use:ref={[clickOutside(a), escape(b)]}.