Comments (9)
Not niche. I'm also trying to create multiple things where if you click outside any of them, they close.
Like... imagine an image gallery. Pretty big use case right there.
In my case it's swatches using react-color and trying to do something like
<Swatch ref={someRef} />
<Swatch ref={anotherRef} />
from use-onclickoutside.
I updated my listener
method to this which allows me to pass a single ref or an array of refs.
const listener = (event: PossibleEvent) => {
const shouldTrigger = !Array.of(refs)
.flat()
.some(
(ref) => !ref.current || ref.current.contains(event.target as Node),
)
if (shouldTrigger && handler) handler(event)
}
from use-onclickoutside.
Could you describe an example use case in more detail?
from use-onclickoutside.
let's say we have two modals on the screen, both in portals, and we want to close both of them if the user clicks the space outside of either one of them
from use-onclickoutside.
But you never want to close any of them if a user clicks inside any of them? Do those modals stack/overlap?
from use-onclickoutside.
they wouldnt stack/overlap, no, but we'd want to detect a click outside of either one of them
from use-onclickoutside.
This seems like a rather less popular use case. I would recommend composing this in your codebase like this:
export default (refs, handler) => refs.forEach(ref => useOnClickOutside(ref, handler))
Or just establish parent-child relationship and set up a single useOnClickOutside
hook in each modal with the same handler plugged to them. If 2 handlers will call smth like setShow(false)
then React will just bailout from the second processing because your state will already be false
, no harm done.
from use-onclickoutside.
export default (refs, handler) => refs.forEach(ref => useOnClickOutside(ref, handler))
won't work because if you click inside modal 2, you're also clicking outside modal 1, so the callback will trigger, when in reality you want it to trigger only when you click outside of either modal
from use-onclickoutside.
Right - no of the proposes approaches would work for you. I still believe that this use case is rather niche though and I wouldn't like overloading the implementation.
If we can come up with a neat implementation then I could consider merging it. At the moment there is no way to configure containment check, so maybe if we would make this configurable it would solve your issue as well? A very WIP implementation could look like this:
export default function useOnClickOutside(
refOrContainsCheck: React.RefObject<HTMLElement> | (node: Node) => boolean,
handler: Handler | null,
) {
if (!isBrowser) {
return
}
const latestRef = useLatest({
handler,
contains: typeof refOrContainsCheck === 'function'
? refOrContainsCheck
: node => {
const refNode = refOrContainsCheck.current
return !!refNode && refNode.contains(node)
}
})
useEffect(() => {
if (!handler) {
return
}
const listener = (event: PossibleEvent) => {
const { contains, handler } = latestRef.current
if (!handler || contains(event.target as Node)) {
return
}
handler(event)
}
events.forEach(event => {
document.addEventListener(event, listener, getOptions(event))
})
return () => {
events.forEach(event => {
document.removeEventListener(event, listener, getOptions(
event,
) as EventListenerOptions)
})
}
}, [!handler])
}
Then you could do smth like this:
useOnClickOutside(
targetNode => refs.some(ref => ref.current.contains(targetNode),
handler,
)
from use-onclickoutside.
Related Issues (14)
- Disabling useOutsideClick callback for specified elements HOT 12
- Logging just to ask some questions HOT 2
- Doesn't handle portals HOT 4
- How this package works so it uses event listeners effectively? HOT 2
- How to test a component using this hook? HOT 1
- Add `capture` option for event handler? HOT 5
- [Question] Why does it use "mousedown" and not "click"? HOT 10
- Clashes with mouse down events creating the element HOT 2
- Don't trigger when scrolling down on mobile? HOT 1
- Add unit tests
- Feature request: adding/excluding Events HOT 1
- Update peerDependency to react 18 HOT 2
- [Feature Requrest] Option to use `window.addEventListener` rather than `document.addEventListener` HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from use-onclickoutside.