ClickAwayEvent
A headless wrapper that detects clicks outside its subtree and fires a callback. The composable primitive used by Popper and Dropdown.
Overview
ClickAwayEvent is a utility component that attaches a document-level click listener and calls onClickAway when a click occurs outside its children. It renders as a <div> wrapper with no visual styling.
It powers the onClickAway behavior of Popper and Dropdown, but can also be used standalone when you need click-outside detection on a custom element.
Import
import { ClickAwayEvent } from '@unflow/ui/components/ClickAwayEvent';Props
| Prop | Type | Default | Description |
|---|---|---|---|
onClickAway | () => void | — | Called when a click occurs outside the wrapper |
listen | boolean | true | Enables/disables the listener without DOM changes |
ignore | Element | null | — | An element to exclude from click-away detection |
All standard HTMLDivElement props are accepted and forwarded.
Examples
Basic
<ClickAwayEvent onClickAway={() => setOpen(false)}>
<div className="p-4 bg-white shadow rounded">
Dropdown content
</div>
</ClickAwayEvent>Conditionally armed
Use listen={false} to disable the listener without unmounting the component. This preserves the DOM node and any internal state:
<ClickAwayEvent listen={isOpen} onClickAway={handleClose}>
<Menu />
</ClickAwayEvent>Ignoring the trigger element
A common pattern: the button that opens a dropdown should not trigger close when clicked. Pass the button element to ignore:
const buttonRef = useRef<HTMLButtonElement>(null);
<button ref={buttonRef} onClick={toggle}>Open</button>
<ClickAwayEvent
listen={isOpen}
onClickAway={close}
ignore={buttonRef.current}
>
<Dropdown />
</ClickAwayEvent>Implementation notes
Capture phase, not bubble. The click listener is attached with { capture: true }. This makes it fire before React's synthetic event system, which prevents a race condition where the same click that opens a dropdown (on the trigger button) is also immediately caught as a click-away and closes it.
listen vs. unmounting. ClickAwayEvent does not add or remove the listener by toggling the component in/out of the DOM — doing so would cause flickering and state loss in complex dropdowns. Instead, the listen prop conditionally registers and deregisters the addEventListener call, keeping the wrapper in the tree at all times.
Accessibility
ClickAwayEvent is purely behavioral and has no ARIA attributes. The element renders as a <div> — if this introduces an unwanted layout wrapper, you can override its display with className="contents".
ActionCard
A full-width list item that acts as a button or toggle. Used inside dropdowns and command palettes for keyboard-navigable action lists.
Shortcut
A visual keyboard shortcut badge. Renders each key as a styled pill using platform-aware symbols, and optionally registers a global hotkey listener.