npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-onblur

v2.0.1

Published

HOC for Blur (Unfocus) event handling of React component

Downloads

2,412

Readme

react-onblur

HOC for Blur (Unfocus) event handling of React component

Installation

npm i --save react-onblur

What is it?

It is simple HOC function

import withOnBlur from "react-onblur";
// ...
export default withOnBlur(/* args */)(YourReactComponent);

which puts in your component two extra props

setBlurListener: function (callbackOrOptions: Function(event) or Object[, once: Boolean])
unsetBlurListener: function ()

setBlurListener should be called when you want to add events to document.

  • callbackOrOptions: Function or Object.
    • If it is Function, then it will be called (with event arg) once your component is unfocused or a user clicks outside of your component.
    • If it is Object of options, then it can contain there options:
      • onBlur: Function(event), required. It will be called once your component is unfocused or a user clicks outside of your component.
      • once: Boolean, optional. The same that second argument of this function.
      • checkInOutside: Function(domNode, isOutside): Boolean, optional. This function will be called always, when each of selected events are fired (e.g. when a user clicks on element on page or press key). It takes dom element target of an event and a Boolean sign that this element is outside. It should return Boolean value as sign that this element is outside. If it returns true then onBlur will be called. More information in next part of this doc.
  • once: Boolean. If true then unsetBlurListener will be called after callback once your component is unfocused or a user clicks outside of your component.
  • getRootNode: Function(this). Should return parent node, all targets out of this node will handle 'onBlur'.

unsetBlurListener should be called when your want to remove events from document.

(!!!) unsetBlurListener will be called in componentWillUnmount always.

TODO

How can you use it?

You should create new component:

import React, { PureComponent } from "react";
import withOnBlur from "react-onblur";

class DemoComponent extends PureComponent {
  state = {
    isOpened: false
  };

  componentDidUpdate(prevProps, prevState) {
    const { isOpened } = this.state;
    // `setBlurListener` and `unsetBlurListener` props were added by withOnBlur
    const { setBlurListener, unsetBlurListener } = this.props;

    if (isOpened !== prevState.isOpened) {

      // if our list was opened, then we will add listeners,
      if (isOpened) setBlurListener(this.onBlur);
      // else we will remove listeners
      else unsetBlurListener();

      // or
      // if (isOpened) setBlurListener(this.onBlur, true);

      // or
      // if (isOpened) setBlurListener({ onBlur: this.onBlur, once: true })
    }
  }

  onClickOpen = () => this.setState({ isOpened: true });
  onBlur = () => this.setState({ isOpened: false });

  render() {
    return (
      <div>
        <button onClick={this.onClickOpen}>
          Open list
        </button>
        {this.state.isOpened && (
          <ul>
            // ... list items
          </ul>
        )}
      </div>
    );
  }
}

export default withOnBlur({ debug: true })(DemoComponent);

Next, you can use this component in your App:

  function App() {
    return (
      <div className="App">
        <div>
          <button>Outside button</button>
        </div>
        <DemoComponent />
        <div>
          <button>Second outside button</button>
        </div>
      </div>
    );
  }

HOC function arguments

| args | type | default | description | | - | - | - | - | | listenClick | bool | true | when true will add mousedown event for document | listenTab | bool | true | when true will add keyup and keydown listeners for document to check Tab key press | listenEsc | bool | true | when true will add keydown event for document to check Esc key is pressed | debug | bool | false | when true will write debug messages to console | autoUnset | bool | false | if true then unsetBlurListener will be called after callback action call once your component is unfocused or user will click outside of your component

Example

import withOnBlur from "react-onblur";
// ...
export default withOnBlur({
  listenClick: true,
  listenTab: false,
  debug: true,
  autoUnset: true
})(YourReactComponent);

What is checkInOutside? And why you should use it?

If you use ReactDOM.createPortal then you can put element to another parent and it will not be child by DOM tree. But you can use checkInOutside to say about it to react-onblur.

import React, { PureComponent } from "react";
import ReactDOM from 'react-dom';
import withOnBlur, { isDomElementChild } from "react-onblur";

class DemoPortalComponent extends PureComponent {
  state = {
    isOpened: false
  };

  domMenu = React.createRef();

  componentDidUpdate(prevProps, prevState) {
    const { isOpened } = this.state;
    const { setBlurListener, unsetBlurListener } = this.props;
    if (isOpened && isOpened !== prevState.isOpened) {
      setBlurListener({
        checkInOutside: this.checkInOutside,
        onBlur: this.onBlur,
        once: true
      })
    }
  }

  onClickOpen = () => this.setState({ isOpened: true });

  onBlur = () => this.setState({ isOpened: false });

  checkInOutside = (element, isOutside) => (
    // if it is in outside then we should check that it is not in our list,
    // which was moved to body by createPortal
    // For it we can use `isDomElementChild(parent, node)` from `react-onblur`
    // and if element is child of list then it returns false.
    isOutside && !isDomElementChild(this.domMenu.current, element)
  );

  render() {
    return (
      <div>
        <button onClick={this.onClickOpen}>
          Open list
        </button>
        {this.state.isOpened && (
          ReactDom.createPortal(
            <ul ref={this.domMenu}>
              // ... list items
            </ul>,
            document.querySelector('body')
          )
        )}
      </div>
    );
  }
}

export default withOnBlur()(DemoPortalComponent);

isDomElementChild

Check that node is child of parent.

isDomElementChild: Function(parent: DomNode, node: DomNode): Boolean
import withOnBlur, { isDomElementChild } from "react-onblur";

isDomElementChild(document.querySelector('body'), document.querySelector('div'));
// true for <body><div>1</div></body>

Demo GIF

Alt Text

Demo video

https://monosnap.com/file/gUeMnlLBE29xKzytdXsxBcZOtkpEtm

Example sandbox

https://codesandbox.io/embed/n9r236n2xl

Live Demo

https://n9r236n2xl.codesandbox.io/