Code Monkey home page Code Monkey logo

react-click-outside's Introduction

React Click Outside

Build Status npm

Enhance a React component with a Higher Order Component that provides click outside detection.

Note: React 0.14 required for version >= 2.x. This assumes react and react-dom is installed in your project. Continue using version 1.x for React 0.13 support.

Note: Use version >= 2.3.0 to get rid of React.createClass warnings in React 15.5.

Usage

Installation:

npm install react-click-outside

Some component that you wish to enhance with click outside detection:

const createReactClass = require('create-react-class');
const enhanceWithClickOutside = require('react-click-outside');
const React = require('react');

const Dropdown = createReactClass({
  getInitialState() {
    return {
      isOpened: false,
    };
  },

  handleClickOutside() {
    this.toggle();
  },

  toggle() {
    this.setState({ isOpened: !this.state.isOpened });
  },

  render() {
    ...
  },
});

module.exports = enhanceWithClickOutside(Dropdown);

Note: There will be no error thrown if handleClickOutside is not implemented.

wrappedRef prop

Use the wrappedRef prop to get access to the wrapped component instance. For example:

// Inside a component's render method
<Dropdown
  wrappedRef={instance => { this.toggle = instance.toggle; }}
/>

// Now you can call toggle externally
this.toggle();

Details

The enhanceWithClickOutside function wraps the provided component in another component that registers a click handler on document for the event capturing phase. Using the event capturing phase prevents elements with a click handler that calls stopPropagation from cancelling the click event that would eventually trigger the component's handleClickOutside function.

Why not a mixin?

There are some mixins that provide click outside detection functionality, but they prevent the component from implementing the componentDidMount and componentWillUnmount life cycle hooks. I recommend not using a mixin for this case.

Limitations

  • IE9+ due to the usage of the event capturing phase.

Not working on iOS?

If the handleClickOutside handler is not firing on iOS, try adding the cursor: pointer css style to the <body> element. There are many ways to achieve this, here is just one example:

if ('ontouchstart' in document.documentElement) {
  document.body.style.cursor = 'pointer';
}

If your app already has a way for mobile detection (e.g. Modernizr), you may want to use that instead.

See issue #4 for a discussion.

License

MIT

react-click-outside's People

Contributors

kentor avatar rdiazv avatar stevenla avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

react-click-outside's Issues

Handle key press

Could you add a key down listener for esc to trigger handleClickOutside. This will improve accessibility for models and drop downs.

Ignore clicks on scrollbars

Great plugin. One problem, clicking and dragging the scrollbar causes the document click event to fire. I know right? Who uses scrollbars and not the wheel...

I'm happy to PR this but wanted to discuss first how to handle it. It doesn't seem like theirs a way to nativly detect when a document click originates from a scrollbar without additional work measuring screen dimensions.

Thoughts?

Please add a change log

I noticed there is no change log file in the repo and only 1 release in github releases.

It will be most appreciated to have one so we know what happens between each version, I wanted to upgrade from 2.3.1 to 3.0.1 and had to go to the commit history (thankfully it's a short one) to understand the changes.

Thanks

Does position of component affect handleClickOutsided handler?

I am running into a problem where handleClickOutside is called every time I click anywhere on screen, even when I am not clicking outside the component.

Could this be due to the fact that my component is positioned absolutely and not statically or relatively?

Add exception

Hi!
I have a button and a list.
button opens and closes the list
it is necessary that when the list is open, the event does not work on a click on the button

how can i add an exception?

Click and drag initiated from inside popover still closes it

A handleClickOutside should not be triggered when user starts a click that in initiated inside an element, mouse is dragged outside of the element and then released.

When using this package with popovers with inputs in side them, users can very easily accidentally close the popovers when trying to select and highlight text inside a popover.

can we stop parent component events with stopPropagation

we have multiple parent child components. if we added react-click-outside in child level component how we can stop the event propagation. currently it is not working for us.

Parent

  • Sub component 1

    • child 1
      • child 2 ( we have implemented react-click-outside in this component )
  • Sub component 2

    • navigation

we are unable to stop the event propagation in navigation or other components.

What we are trying to achieve is checking form outside click event and inform user with confirm box so that you are navigating outside the form with skipping form value changes. with confirm OK button we want to continue current event trigger operation.

we are using 1.x version for compatibility reasons.

Doesn't work if you click outside, over an iFrame

Use case:

You have a menu A.
You have a callback X, which is to be triggered if a click is detected outside A (using this library).
Somewhere on the page, you have an iFrame B.
When A is visible, and you click anywhere on the page, X gets invoked (working correct).
When A is visible, and you click anywhere over B, X doesn't get invoked (bug).
version: 3.0.0

use of hoist-non-react-statics

Hello everybody,

like the react-redux connect() enhancer, react-click-outside should hoist all non-react statics properties.

Would you want a PR ?

Support for react 15?

When building with react 15 I get the following error:

ModuleNotFoundError: Module not found: Error: Cannot resolve module 'react/lib/Object.assign' in C:\Code\......\my_proj\node_modules\react-onclickoutside

Changing line 2 in decorator.js to:

var objectAssign = require('object.assign');

solves the problem.

Server side support

Does this work while rendering on the server side. I am trying to wrap a component on the server side but the handleClickOutside does not seem to be called. Is there any way to make this work?

Handle touch devices

I would like to use this component but need it to handle touch events. This would add some code but increase the value. Essentially, I think we'd need to listen for adapt code from https://github.com/alexgibson/tap.js to listen for touchstart, determine whether the action is a scroll or a "tap", and respond to taps.

Are you open to a PR attempting to implement this?

Unable to find node on an unmounted component in React 16.0.0

I was trying to implement such a feature by myself but nothing worked as described on several websites. So I've encountered this package and it also does not work with React 16.0.0. I get the "Unable to find node on an unmounted component" error. Did anyone experience this problem?

It comes from usage of the ReactDOM.findDOMNode method. It's really strange because the component is mounted (I've checked that). Maybe it's a bug in React 16.0.0?

stopPropagation

In the docs the following caught my eye:

Using the event capturing phase prevents elements with a click handler that calls stopPropagation from cancelling the click event that would eventually trigger the component's handleClickOutside function.

Isn't the described situation not what you would want? When I call stopPropagation in some click handler I expect handleClickOutside not to be called?

Defunct with parcel, babel 7

This modules doesn't play well with parcel and babel 7.

package.json:

{
  ...
  "main": "src/index.js",
  "scripts": {
    "start": "parcel html/index.html"
  },
  "devDependencies": {
    "@babel/core": "^7.6.0",
    "@babel/plugin-proposal-class-properties": "^7.5.5",
    "@babel/preset-env": "^7.6.0",
    "@babel/preset-react": "^7.0.0",
    "eslint": "^6.4.0",
    "eslint-config-standard": "^14.1.0",
    "eslint-plugin-import": "^2.18.2",
    "eslint-plugin-jsx": "^0.1.0",
    "eslint-plugin-node": "^10.0.0",
    "eslint-plugin-promise": "^4.2.1",
    "eslint-plugin-react": "^7.14.3",
    "eslint-plugin-standard": "^4.0.1",
    "parcel-bundler": "^1.12.3"
  },
  "dependencies": {
    "react": "^16.9.0",
    "react-dom": "^16.9.0",
    "react-trello": "^2.2.3"
  }
}

.babelrc:

{
  "presets": ["@babel/preset-env", "@babel/preset-react"],
  "plugins": ["@babel/plugin-proposal-class-properties"]
}

If I import react-click-outside with the settings above, I get this error:

react-click-outside/build/index.js: Plugin/Preset files are not allowed to export objects, only functions. In /home/mike/workspace/burnmaster/node_modules/react-click-outside/node_modules/babel-preset-react/lib/index.js

I have no idea why this happens. I've tried to reproduce the issue using normal require with babel-node, but I couldn't get it to produce the same error.

Element.closest() support?

I have a component wrapped with enhanceWithClickOutside HOC. Can I use event target.closest() or currentTarget.closest() to conditionally trigger event?

Warnings with React StrictMode

react-click-outside's use of findDOMNode triggers a warning when used with React.StrictMode.

https://reactjs.org/docs/strict-mode.html

Warning: findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of PopoverDetectOutside which is inside StrictMode. Instead, add a ref directly to the element you want to reference.

("PopoverDetectOutside" is the component wrapped using react-click-outside)

Specific issue:

https://reactjs.org/docs/strict-mode.html#warning-about-deprecated-finddomnode-usage

Looking at the implementation, would it be possible to assign the ref as the result of a createRef, calling the wrappedRef callback during componentDidMount using this.ref.current?

https://reactjs.org/docs/refs-and-the-dom.html

How to test components with react-click-outside

When a component is exported with enhanceWithClickOutside, enzyme can't find the component in it.

For example, the following fails:

test('Renders the root div', () => {
  const component = shallow(<MyComponent />);
  expect(component).toContain('div#root-div');
});

MyComponent.js

function MyComponent() {
  // ...
  return (
    <div id="root-div">
      {/* ... */}
    </div>
  );
}
export default enhanceWithClickOutside(MyComponent)

What is the workaround?

IE11

I have a drop down menu that allows for overflow-y scrolling. Currently in IE11 if a user clicks on the scroll bar within the drop down it is treated as an onBlur/clickoutside event.

Possible to call React.findDOMNode on unmounted component

It might be possible since the click handler is queued in the event loop, and the component may unmount before it gets executed.

Seeing

Invariant Violation
findDOMNode was called on an unmounted component.

in a production app

Outside click sometimes ignored with multiple containers

I'm using this package for my settings panel
https://github.com/TeamWertarbyte/material-ui-settings-panel

I pass down "ExpandablePanel" components as children into my wrapper.
Sometimes I can open all my panels.
The expected behaviour is that only one! panel at a time could be open.

Seems that the outsideClickHanlder is sometimes ignored when clicking another ExpandablePanel. See the live demo https://teamwertarbyte.github.io/material-ui-settings-panel/

This wrapper broke the prototype chain in inheritance

Once a component is wrapped, it can't be inherited to access the parent prototype method. Here is the example code:

@ClickOutside
class Parent extends React.Component {
  someMethod() {
    console.log('call parent');
  }
}

class Child extends Parent {}

console.log(Child.prototype.someMethod); // undefined

I think make one more layer inheritance for wrapping would be better.

Add exception

Hi! Can I define some element as exception of handleClickOutside?
I need to prevent this function when I click on specific element.

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.