Skip to content
Sensors

useOnClickOutside

Listen for clicks outside of a target element. Useful for closing modals, dropdowns, and popovers when the user clicks elsewhere.

Click Outside Detection
Open

Click outside the blue panel to close it. The counter tracks outside clicks.

Outside Clicks
0
Click outside this panel
import {
const useRef$: {
<T = any>(initialValue: null): Ref$<T | null>;
<T = any>(initialValue: T): Ref$<T>;
<T = any>(): Ref$<T | null>;
}
useRef$
} from "@usels/core";
import {
const useOnClickOutside: {
<T extends OnClickOutsideOptions<false>>(target: MaybeEventTarget, handler: OnClickOutsideHandler<T>, options?: T): Fn;
<T extends OnClickOutsideOptions<true>>(target: MaybeEventTarget, handler: OnClickOutsideHandler<T>, options: T): OnClickOutsideReturn;
}
useOnClickOutside
} from "@usels/web";
import {
function useObservable<T>(): Observable<T | undefined> (+3 overloads)

A React hook that creates a new observable

@paraminitialValue The initial value of the observable or a function that returns the initial value

@seehttps://www.legendapp.com/dev/state/react/#useObservable

useObservable
} from "@usels/core";
function
function Dropdown(): JSX.Element
Dropdown
() {
const
const el$: Ref$<HTMLDivElement | null>
el$
=
useRef$<HTMLDivElement>(): Ref$<HTMLDivElement | null> (+2 overloads)

Core (framework-agnostic) version of useRef$. Creates an observable element ref with opaque wrapping.

  • non-null value → Ref$<T>: current, get(), peek() return T
  • null / no arg → Ref$<T | null>: current, get(), peek() return T | null

Nullability is expressed via the type parameter, mirroring T | null at the call site.

useRef$
<
interface HTMLDivElement
HTMLDivElement
>();
const
const isOpen$: any
isOpen$
=
useObservable<unknown>(value: Promise<unknown> | (() => unknown) | unknown, deps?: DependencyList): any (+3 overloads)

A React hook that creates a new observable

@paraminitialValue The initial value of the observable or a function that returns the initial value

@seehttps://www.legendapp.com/dev/state/react/#useObservable

useObservable
(false);
useOnClickOutside<OnClickOutsideOptions<false>>(target: MaybeEventTarget, handler: OnClickOutsideHandler<OnClickOutsideOptions<false>>, options?: OnClickOutsideOptions<false> | undefined): Fn (+1 overload)
useOnClickOutside
(
const el$: Ref$<HTMLDivElement | null>
el$
, () => {
const isOpen$: any
isOpen$
.
any
set
(false);
});
return (
<
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
<
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
DOMAttributes<HTMLButtonElement>.onClick?: MouseEventHandler<HTMLButtonElement> | undefined
onClick
={() =>
const isOpen$: any
isOpen$
.
any
set
(true)}>Open</
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
>
{
const isOpen$: any
isOpen$
.
any
get
() && <
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
RefAttributes<HTMLDivElement>.ref?: Ref<HTMLDivElement> | undefined

Allows getting a ref to the component instance. Once the component unmounts, React will set ref.current to null (or call the ref with null if you passed a callback ref).

ref
={
const el$: Ref$<HTMLDivElement | null>
el$
}>Dropdown content — click outside to close</
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>}
</
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
);
}

Pass CSS selectors or element refs to the ignore option to exclude certain elements from triggering the handler.

// @noErrors
import { useRef$ } from "@usels/core";
import { useOnClickOutside } from "@usels/web";
function Component() {
const el$ = useRef$<HTMLDivElement>();
const trigger$ = useRef$<HTMLButtonElement>();
useOnClickOutside(
el$,
() => {
// won't fire when clicking the trigger button or any .ignore-me element
},
{
ignore: [trigger$, ".ignore-me"],
}
);
return (
<div>
<button ref={trigger$}>Toggle</button>
<div ref={el$}>Panel</div>
</div>
);
}

Set detectIframe: true to also trigger the handler when focus moves to an iframe element outside the target.

useOnClickOutside(el$, handler, { detectIframe: true });

By default the event listener uses the capturing phase (capture: true). Set capture: false to use the bubbling phase instead.

useOnClickOutside(el$, handler, { capture: false });
ParameterTypeDescription
targetMaybeEventTarget-
handlerOnClickOutsideHandler<T>-
optionsT-
OptionTypeDefaultDescription
ignore(string | MaybeEventTarget)[]-List of elements or CSS selectors that should not trigger the handler.
capturebooleantrueUse capturing phase for internal event listener.
detectIframebooleanfalseRun handler function if focus moves to an iframe.
controlsControlsfalseReturn control functions (stop, cancel, trigger) instead of just stop.
windowWindowSource--

OnClickOutsideReturn

NameTypeDescription
stopFnRemove all event listeners
cancelFnPrevent the next outside click from triggering the handler
trigger(event: Event) => voidManually trigger the handler with a given event

View on GitHub