✨ Introducing react-cool-onclickoutside: A React hook to listen for clicks outside of the component(s)
Tags: react, hook, opensource, javascript
Published: 2020-01-15 10:29:29

[react-cool-onclickoutside](https://github.com/wellyshen/react-cool-onclickoutside) is a React [hook](https://reactjs.org/docs/hooks-custom.html#using-a-custom-hook) to trigger callback when user clicks outside of the target component(s) area. It's a useful logic for UI interaction design (IxD) like dismiss a dropdown menu, modal or tooltip etc. You can explore the [features](#features) section to learn more.

⚡️ Live demo: https://react-cool-onclickoutside.netlify.app

## Features

- 🎣 Listens for clicks outside based on React [hook](https://reactjs.org/docs/hooks-custom.html#using-a-custom-hook).
- 👯‍♀️ Supports multiple [refs](https://reactjs.org/docs/refs-and-the-dom.html) to cover more use cases.
- 🧻 Uses [passive event listeners](https://developers.google.com/web/tools/lighthouse/audits/passive-event-listeners) to improve scrolling performance.
- ⛔ Scrollbar can be excluded from the callback of outside clicks.
- 🙈 [Ignores certain elements](https://github.com/wellyshen/react-cool-onclickoutside#ignore-elements-by-css-class-name) during the event loop.
- 🙉 Enables you to [stop listening for outside clicks](#disabling-the-event-listener) when needed.
- 🪟 [Detects iframe clicks](https://github.com/wellyshen/react-cool-onclickoutside/blob/master/README.md#detecting-iframe-clicks) for better DX.
- 🔩 Supports custom refs for [some reasons](https://github.com/wellyshen/react-cool-onclickoutside#use-your-own-ref).
- 📜 Supports [TypeScript](https://www.typescriptlang.org) type definition.
- 🗄️ Server-side rendering friendly.
- 🦔 Tiny size ([< 1kB gzipped](https://bundlephobia.com/result?p=react-cool-onclickoutside)). No external dependencies, aside for the `react`.

## Usage

Common use case.

```js
import { useState } from "react";
import useOnclickOutside from "react-cool-onclickoutside";

const Dropdown = () => {
  const [openMenu, setOpenMenu] = useState(false);
  const ref = useOnclickOutside(() => {
    setOpenMenu(false);
  });

  const handleClickBtn = () => {
    setOpenMenu(!openMenu);
  };

  return (
    <div>
      <button onClick={handleClickBtn}>Button</button>
      {openMenu && <div ref={ref}>Menu</div>}
    </div>
  );
};
```

Support multiple refs. Callback only be triggered when user clicks outside of the registered components.

```js
import { useState } from "react";
import useOnclickOutside from "react-cool-onclickoutside";

const App = () => {
  const [showTips, setShowTips] = useState(true);
  const ref = useOnclickOutside(() => {
    setShowTips(false);
  });

  return (
    <div>
      {showTips && (
        <>
          <div ref={ref}>Tooltip 1</div>
          <div ref={ref}>Tooltip 2</div>
        </>
      )}
    </div>
  );
};
```

## Ignore Elements by CSS Class Name

You can tell [react-cool-onclickoutside](https://github.com/wellyshen/react-cool-onclickoutside) to ignore certain elements during the event loop by the `ignore-onclickoutside` CSS class name. If you want explicit control over the class name, use the `ignoreClass` option.

```js
import { useState } from "react";
import useOnclickOutside from "react-cool-onclickoutside";

// Use default CSS class name
const App = () => {
  const ref = useOnclickOutside(() => {
    // Do something...
  });

  return (
    <div>
      <div ref={ref}>I'm a 🍕</div>
      <div>Click me will trigger the event's callback</div>
      <div className="ignore-onclickoutside">
        Click me won't trigger the event's callback
      </div>
    </div>
  );
};

// Use the CSS class name that you defined
const App = () => {
  const ref = useOnclickOutside(
    () => {
      // Do something...
    },
    { ignoreClass: "my-ignore-class" }
  );

  return (
    <div>
      <div ref={ref}>I'm a 🍕</div>
      <div>Click me will trigger the event's callback</div>
      <div className="my-ignore-class">
        Click me won't trigger the event's callback
      </div>
    </div>
  );
};
```

## Disabling the Event Listener

In case you want to disable the event listener for performance reasons or fulfill some use cases. We provide the `disabled` option for you. Once you set it as `true`, the callback won’t be triggered.

```js
import { useState } from "react";
import useOnclickOutside from "react-cool-onclickoutside";

const App = () => {
  const [disabled, setDisabled] = useState(false);
  const ref = useOnclickOutside(
    () => {
      // Do something...
    },
    { disabled }
  );

  const handleBtnClick = () => {
    setDisabled(true);
  };

  return (
    <div>
      <button onClick={handleBtnClick}>
        Stop listening for outside clicks
      </button>
      <div ref={ref}>I'm a 🍎</div>
    </div>
  );
};
```

---

For more details, please check the GitHub: https://github.com/wellyshen/react-cool-onclickoutside

You can also install this package is distributed via [npm](https://www.npmjs.com/package/react-cool-onclickoutside).

```sh
$ yarn add react-cool-onclickoutside
# or
$ npm install --save react-cool-onclickoutside
```