New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG] Stop scrolling from interfering with dragging #185
Comments
Are you finding that scrolling is happening at all when you drag on a component? It should be blocked - ideally we'd only block if you touched in the same direction as defined in You can combine <motion.div dragDirectionLock drag="x" /> |
Thanks! That's at least a step in the right direction 👍 I had been testing by scrolling in screen space below the list, but that's actually a much bigger issue if/when the list occupies the whole screen. Guessing there's not a way to unblock scrolling right now then? |
Not at the moment sadly. I believe there might be a possible fix. But the problem ultimately is that to detect whether a user is dragging and in which direction we need to block the touch event from scrolling, or at least start blocking it before scrolling. But there's a distance a user can swipe within a single event that initiates scrolling. Once it's started, it's unblockable. Mobile browsers 👍 |
What about allowing the user to control whether In my case, there's no horizontal scroll space available, so a drag on the x axis isn't going to affect it. Scrolling on the y axis shouldn't interfere because of the direction lock, right? |
I have a motion component that I want to drag on |
I just build a nice slider using the Had to look into I know this is one of those difficult issues, and we can agree that you don't want scrolling to occur while dragging. I made "fix" that determines if we are scrolling or dragging based on the initial velocity in function Example() {
const [allowScroll, setAllowScroll] = useState(false)
useEffect(() => {
if (allowScroll) {
const handleTouch = event => {
event.stopPropagation()
}
document.documentElement.addEventListener('touchmove', handleTouch)
return () => {
document.documentElement.removeEventListener('touchmove', handleTouch)
}
}
}, [allowScroll])
return <motion.div drag="x" onDragStart={(event, info) => {
setAllowScroll(Math.abs(info.delta.y) > Math.abs(info.delta.x))
}}
/>
} |
Not sure if I fully understand why this can't currently work - but for anybody who happens upon this thread looking for a solution, I did notice that the react-swipeable-views package does seem to achieve this to some extent. What I would find useful is the ability to scroll vertically but at the same time use framer-motion for dragging on the x-axis. Perhaps it could be opt-in to avoid the problem mentioned by @InventingWithMonster ? I think this is quite a common use case for many UIs (eg Tinder-style "swipe" interfaces) |
Alternatively, for anyone looking for vertical scrolling while being able to drag an element horizontally, you can use react-spring. I have set up a quick codesandbox example: |
Has this been implemented yet? I am also facing the same issue ... I have a list of items that is longer than the screen and need to scroll down but he drag="x" keeps preventing it |
Thank you very much, this solved my Carousel issue ❤ Have you seen any issues with it? The X drag was hit a little bit in responsiveness, but it's worth being able to scroll. |
Do you have a working example of this? Can't get this to work in a reliable manner |
I have this that used to work (in 1.6.7), but not in the latest version. const Example = () => {
const clientYStart = useRef(null);
const clientXStart = useRef(null);
const horizontalScrollStart = useRef(0);
const isDragging = useRef(false);
const isScrolling = useRef(false);
return (
<div
onTouchStart={e => {
// Track current direction
const touch = e.targetTouches[0];
clientYStart.current = touch.clientY;
clientXStart.current = touch.clientX;
horizontalScrollStart.current = horizontalScroll.get();
}}
onTouchMove={e => {
const touch = e.targetTouches[0];
const deltaY = Math.abs(touch.clientY - clientYStart.current);
const deltaX = Math.abs(touch.clientX - clientXStart.current);
if (isDragging.current) {
return;
}
if (isScrolling.current) {
e.stopPropagation();
return;
}
if (deltaX > deltaY) {
isDragging.current = true;
} else {
isScrolling.current = true;
e.stopPropagation();
}
}}
onTouchEnd={e => {
if (isScrolling.current) {
horizontalScroll.set(horizontalScrollStart.current);
}
isDragging.current = false;
isScrolling.current = false;
}}>
{items.map(item => (
<motion.div drag={'x'} style={{ x: horizontalScroll }}></motion.div>
))}
</div>
);
}; |
I'm also dealing with this right now. I have drag='x' with dragDirectionLock enabled on an element that can have overflow-y which is set to scroll, but on mobile I'm not able to scroll it. Perhaps implementing a way to cancel a drag in progress would be helpful? For example, a way to cancel the drag in the onDirectionLock callback if the axis returned is 'y'. Not sure if that would be feasible though; just spitballing. |
I just want to maintain body scroll, but doesn't matter if i set |
As temporary solution we use react-use-gesture instead of drag properties and animate everything with |
@dimitriirybakov Can you show the basic pattern how you use that to fix this? I am not above copying as this one has stumped me. |
@InventingWithMonster well, it's basically something like this
|
Can confirm I also have this issue as well. Is this issue on the roadmap of getting fixed in the next major/minor version? |
i also have this issue with a list taking all my mobile screen and i cant scroll y-axis because of the listItems having drag=x.. |
Has anyone been able to solve this? Been stuck on this for hours. |
Hi! is there a way to make this work with motion dragcontraints? im tried this and the scrolling seems to work along with the x drag, but i have to take out the framer motion "drag" property to acomplish. This breaks the dragContraints property. |
@danilockthar I just did this last night and it seemed to work... const myComponent = ({children}) => {
const animation = useAnimation({
x: 0,
transition: {
type: "spring",
stiffness: 1,
},
});
const bind = useDrag(
(state) => {
if (state.dragging) {
animation.start({ x: state.movement[0] });
} else {
animation.start({ x: 0 });
}
},
{
axis: "x",
}
);
return (
<motion.div
{...bind()}
animate={animation}
>
{children}
</motion.div>
)
} |
This looks great Benjamin ! Thank you very much. It works great :D |
Thanks @BenjaminCorey Where did you import the |
Using this solution with vertical list I have the same problem, the event gets locked infinitely |
I think I'm having the opposite issue here in that I have my own scroll-blocking in place using https://www.npmjs.com/package/body-scroll-lock. And framer-motion's built-in blocking appears to break mine after the first drag by colliding with body-scroll-lock. Not sure why yet, perhaps both are modifying body style? Is there a way to tell framer-motion not to attempt any touch scroll blocking because I'm already handling it? My entire UI is in a fullscreen modal - so I know that when the modal is open I want to only allow touch events through that initiated inside the model. |
The way it works is by applying touch-action style to the element - maybe
you can override it with an !important rule and see if that fixes it?
…On Tue, 6 Oct 2020 at 05:18, Emery Denuccio ***@***.***> wrote:
I think I'm having the opposite issue here in that I have my own
scroll-blocking in place using
https://www.npmjs.com/package/body-scroll-lock. And framer-motion's
built-in blocking appears to break mine after the first drag by colliding
with body-scroll-lock. Not sure why yet, perhaps both are modifying body
style?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#185 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AB34WKQOHFXWBM3HWSS56KTSJKD7VANCNFSM4IBETH2A>
.
|
Hey @omarryhan do you found the way how to handle it? |
Hey @Dm1Korneev Here's the code I used: https://github.com/omarryhan/trendzz/blob/master/components/WithSlide/Component.tsx And for the live demo, go to: https://trendzz.netlify.app and try swiping a repo card to the left. Hope that helps. Edit: On desktop, you'll need to click and drag from either the very top of the card or the very bottom. Because if you click in the middle, it will trigger an onclick event which will open a new tab. |
Any news on this? |
Scrolling interfering with dragging because of Below example prevents animation when dragging horizontally and scrolling:
|
Is your feature request related to a problem? Please describe.
If you render a list of
drag="x"
components and try to scroll down on a touch device, a small amount of horizontal drag happens on each element that your finger touches.Describe the solution you'd like
A generic solution could be to allow the variant styles to override the styles from the drag.
Describe alternatives you've considered
I also tried overriding by passing
transform
styles directly to themotion.div
element.A more specific version of this might be adding a
dragThreshold
prop that would specify the offsets that the gesture must pass before theonDragStart
event is called.Another option might be having some way to cancel the animation (but not the event) from the
onDrag
handler.The text was updated successfully, but these errors were encountered: