Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/wellyshen/react-cool-onclickoutside

😎 πŸ–± React hook to listen for clicks outside of the component(s).
https://github.com/wellyshen/react-cool-onclickoutside

elements hook onclickoutside react typescript

Last synced: 4 days ago
JSON representation

😎 πŸ–± React hook to listen for clicks outside of the component(s).

Awesome Lists containing this project

README

        

# REACT COOL ONCLICKOUTSIDE

This 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 check the [features](#features) section to learn more.

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

❀️ it? ⭐️ it on [GitHub](https://github.com/wellyshen/react-cool-onclickoutside/stargazers) or [Tweet](https://twitter.com/intent/tweet?text=With%20@react-cool-onclickoutside,%20I%20can%20build%20UI%20components%20efficiently.%20Thanks,%20@Welly%20Shen%20🀩) about it.

[![build status](https://img.shields.io/github/workflow/status/wellyshen/react-cool-onclickoutside/CI?style=flat-square)](https://github.com/wellyshen/react-cool-onclickoutside/actions?query=workflow%3ACI)
[![coverage status](https://img.shields.io/coveralls/github/wellyshen/react-cool-onclickoutside?style=flat-square)](https://coveralls.io/github/wellyshen/react-cool-onclickoutside?branch=master)
[![npm version](https://img.shields.io/npm/v/react-cool-onclickoutside?style=flat-square)](https://www.npmjs.com/package/react-cool-onclickoutside)
[![npm downloads](https://img.shields.io/npm/dm/react-cool-onclickoutside?style=flat-square)](https://www.npmtrends.com/react-cool-onclickoutside)
[![npm downloads](https://img.shields.io/npm/dt/react-cool-onclickoutside?style=flat-square)](https://www.npmtrends.com/react-cool-onclickoutside)
[![gzip size](https://badgen.net/bundlephobia/minzip/react-cool-onclickoutside?label=gzip%20size&style=flat-square)](https://bundlephobia.com/result?p=react-cool-onclickoutside)
[![All Contributors](https://img.shields.io/badge/all_contributors-4-orange?style=flat-square)](#contributors-)
[![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen?style=flat-square)](CONTRIBUTING.md)
[![Twitter URL](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2Fwellyshen%2Freact-cool-onclickoutside)](https://twitter.com/intent/tweet?text=With%20@react-cool-onclickoutside,%20I%20can%20build%20UI%20components%20efficiently.%20Thanks,%20@Welly%20Shen%20🀩)

## 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](#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](#detecting-iframe-clicks) for better DX.
- πŸ”© Supports custom `refs` for [some reasons](#use-your-own-ref).
- πŸ“œ Supports [TypeScript](https://www.typescriptlang.org) type definition.
- πŸ—„οΈ Server-side rendering compatibility.
- πŸ¦” Tiny size ([< 1kB gzipped](https://bundlephobia.com/result?p=react-cool-onclickoutside)). No external dependencies, aside for the `react`.

## Requirement

To use `react-cool-onclickoutside`, you must use `[email protected]` or greater which includes hooks.

## Installation

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
```

## 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 (


Button
{openMenu &&
Menu
}

);
};
```

[![Edit useOnclickOutside demo](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/useonclickoutside-demo-g185l?fontsize=14&hidenavigation=1&theme=dark)

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 (


{showTips && (
<>
Tooltip 1

Tooltip 2

>
)}

);
};
```

## Ignore Elements by CSS Class Name

You can tell `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 the default CSS class name
const App = () => {
const ref = useOnclickOutside(() => {
// Do something...
});

return (


I'm a πŸ•

Click me will trigger the event's callback


Click me won't trigger the event's callback


);
};

// Use your own CSS class name
const App = () => {
const ref = useOnclickOutside(
() => {
// Do something...
},
{
ignoreClass: "my-ignore-class", // Or ["class-1", "class-2"]
}
);

return (


I'm a πŸ•

Click me will trigger the event's callback


Click me won't trigger the event's callback


);
};
```

## 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 to `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 (



Stop listening for outside clicks

I'm a 🍎


);
};
```

## Use Your Own `ref`

In case of you had a ref already or you want to share a ref for other purposes. You can pass in the ref instead of using the one provided by this hook.

```js
const ref = useRef();

useOnclickOutside(
() => {
// Do something...
},
{ refs: [ref] }
);
```

## Detecting Iframe Clicks

Clicks on an `` element won't trigger `document.documentElement` listeners, because it's literally different page with different security domain. However, when clicking on an iframe moves `focus` to its content's window that triggers the main [window.blur](https://developer.mozilla.org/en-US/docs/Web/API/Window/blur_event) event. `react-cool-onclickoutside` in conjunction the `blur` event with [document.activeElement](https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/activeElement) to detect if an iframe is clicked, and execute the provided callback.

The above-mentioned workaround has its caveats:

- Clicks on an iframe will only trigger the provided callback once. Subsequent clicks on iframe will not trigger the callback until focus has been moved back to main window.
- Move focus to iframe via keyboard navigation also triggers the provided callback.

For our convenience, this feature is enabled by default. You can optionally disable it by setting the `detectIFrame` to `false` if you find it conflicting with your use-case.

## API

```js
const ref = useOnclickOutside(callback: (event: Event) => void, options?: object);
```

You must register the `ref` and pass the `callback` to use this hook. Moreover you can access the `event` object via the callback's parameter, default will be [MouseEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent) or [TouchEvent](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent).

```js
const callback = (event) => {
console.log("Event: ", event);
};
```

The `options` object contains the following keys.

| Key | Type | Default | Description |
| ------------------ | ------------------ | ----------------------------- | ------------------------------------------------------------------------------------------------------- |
| `refs` | Array | | For [some reasons](#use-your-own-ref), you can pass in your own `ref(s)` instead of using the built-in. |
| `disabled` | boolean | `false` | Enable/disable the event listener. |
| `eventTypes` | Array | `['mousedown', 'touchstart']` | Which events to listen for. |
| `excludeScrollbar` | boolean | `false` | Whether or not to listen (ignore) to browser scrollbar clicks. |
| `ignoreClass` | string \| string[] | `ignore-onclickoutside` | To ignore certain elements during the event loop by the CSS class name that you defined. |
| `detectIFrame` | boolean | `true` | To disable the feature of [detecting iframe clicks](#detecting-iframe-clicks). |

## Articles / Blog Posts

> πŸ’‘ If you have written any blog post or article about `react-cool-onclickoutside`, please open a PR to add it here.

- Featured on [React Status #172](https://react.statuscode.com/issues/172).

## Contributors ✨

Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):



Welly

πŸ’» πŸ“– 🚧

DmitryScaletta

πŸ›

vardani

πŸ›

Alexey Cherepanov

πŸ’»

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!