use-click-outside

Detect click and touch events outside of specified element
Import

Usage

import { useState } from 'react';
import { Paper, Button } from '@mantine/core';
import { useClickOutside } from '@mantine/hooks';
function Demo() {
const [opened, setOpened] = useState(false);
const ref = useClickOutside(() => setOpened(false));
return (
<>
<Button onClick={() => setOpened(true)}>Open dropdown</Button>
{opened && (
<Paper ref={ref} shadow="sm">
<span>Click outside to close</span>
</Paper>
)}
</>
);
}

API

Hook accepts 3 arguments:

  • handler – function that will be called on outside click
  • events – optional list of events that indicate outside click
  • nodes - optional list of nodes that should not trigger outside click event

Hook returns React ref object that should be passed to element on which outside clicks should be captured.

import { useClickOutside } from '@mantine/hooks';
function Example() {
const handleClickOutside = () => console.log('Clicked outside of div');
const ref = useClickOutside(handleClickOutside);
return <div ref={ref} />;
}

Change events

By default, use-click-outside listens to mousedown and touchstart events, you can change these events by passing an array of events as second argument:

import { useState } from 'react';
import { Paper, Button } from '@mantine/core';
import { useClickOutside } from '@mantine/hooks';
function Demo() {
const [opened, setOpened] = useState(false);
const ref = useClickOutside(() => setOpened(false), ['mouseup', 'touchend']);
return (
<>
<Button onClick={() => setOpened(true)}>Open dropdown</Button>
{opened && (
<Paper ref={ref} shadow="sm">
<span>Click outside to close</span>
</Paper>
)}
</>
);
}

Multiple nodes

In some cases you may want to trigger outside click event for multiple nodes, for example, when dropdown renders in portal. To do so provide third argument with an array of nodes which should not trigger outside click event:

// Will work only with useState, not useRef
import { useState } from 'react';
import { useClickOutside } from '@mantine/hooks';
import { Portal } from '@mantine/core';
function Demo() {
const [dropdown, setDropdown] = useState(null);
const [control, setControl] = useState(null);
useClickOutside(() => console.log('outside'), null, [control, dropdown]);
return (
// We cannot use root element ref as it does not contain dropdown
<div>
<div ref={setControl}>Control</div>
<Portal>
<div ref={setDropdown}>Dropdown</div>
</Portal>
</div>
);
}

TypeScript

Definition

function useClickOutside<T extends HTMLElement = any>(
handler: () => void,
events?: string[] | null,
nodes?: HTMLElement[]
): React.MutableRefObject<T>;

Ref type

By default, use-click-outside returns ref object with React.MutableRefObject<any> type as ref type does not matter in almost all cases. You can specify ref type by passing a type:

const ref = useClickOutside<HTMLDivElement>(onClickOutside);