React-beautiful-dnd: Dragging items with drag handle triggers hover effects of other items in the list

Created on 27 Nov 2018  ·  8Comments  ·  Source: atlassian/react-beautiful-dnd

Bug or feature request?

Bug...?

Expected behavior

When dragging an item without a drag handle, dragging over other items in the list does not trigger their hover effects. I would expect the same to be the case when using a drag handle.

Actual behavior

When I'm dragging an item with a drag handle over other items in the list, the hover effect of those other items gets triggered.

Steps to reproduce

Drag an item by the drag handle over other items.

What version of React are you using?

16.6.3

What version of react-beautiful-dnd are you running?

10.0.2

What browser are you using?

Firefox 63.0.3

Demo

https://codesandbox.io/s/wnylqopyl

Drag handles in the given example only show up on Item hover. Adding to the observed behaviour above, the handle of the dragged item also disappears on drag, which I would expect not to happen.

discussion 🗣❤️ help wanted 👋 investigating 🕵️‍♂️

Most helpful comment

@artooras I was seeing this too with the same setup. I am able to remove those hover events while dragging by adding

const style = snapshot.isDraggingOver ? {
  "pointer-events": "none"
} : {};

to the droppable. I found that tip mentioned in the (phase: dragging): Droppable element docs.

Demo

https://codesandbox.io/s/n9zm6m5j9p

All 8 comments

@artooras I was seeing this too with the same setup. I am able to remove those hover events while dragging by adding

const style = snapshot.isDraggingOver ? {
  "pointer-events": "none"
} : {};

to the droppable. I found that tip mentioned in the (phase: dragging): Droppable element docs.

Demo

https://codesandbox.io/s/n9zm6m5j9p

Excellent, this did indeed solve the problem. Thank you! The only remaining issue is that the drag handle of the dragged item hides on drag. Any ideas how to fix this?

I have seen this before also. I am on the search for a general solution. The trouble with pointer-events: none is that it will stop users being able to scroll scroll containers with their mouse wheel. Not a huge deal as we have auto scrolling, but it is why I have not applied it generically.

I am thinking of applying pointer-events: none to all Draggables during a drag. Currently it is only applied to drag handles. However, this would not stop hover effects on other elements

@artooras The way I keep the drag handle visible while dragging is to pass in the snapshot to whatever function is building up the <Draggable ... /> such that I can ask for snapshot.isDragging. That way I can conditionally render some class that will have the appropriate visibility: hidden; or visible, in this case .show-drag-handle.

renderRow(provided, snapshot) {
  const classNames = {
    "show-drag-handle": this.state.isHovered || snapshot.isDragging
  };

  return (
    <div className={classNames} .../>
  );
}

...

render() {
  return (
    <Draggable ... >
      {(provided, snapshot) => this.renderRow(provided, snapshot)}
    </Draggable/>
  );
}

I'm not familiar enough with the styled-components lib to provide an example with my earlier fork, but I hope this makes sense. I'd love to hear alternatives to this solution though if there's something built-in that I'm missing.

I should mention that whatever element is building up the row needs to have a couple event listeners for the hover event. Something like:

const handleMouseOver = () => {
  this.setState({ isHovered: true });
};

const handleMouseOut = () => {
  this.setState({ isHovered: false });
};

In my example above, for example, these would need to be bound on the div.

Another approach for now.

Have a class on body such as is-dragging when dragging and is-not-dragging when there is no drag. Then only apply the hover styles when is-not-dragging.

.is-not-dragging .target:hover {
 color: red;
}

OK, I managed to keep displaying the handle on drag by using the snapshot.isDraggable of the Draggable:

<Draggable
  index={index}
  draggableId={id}
>
  {(draggable, snapshot) =>
    ...
    <DragHandle
      isDragging={snapshot.isDragging}
      {...draggable.dragHandleProps} 
    />
  }
</Draggable>

and display the DragHandle when dragging:

const DragHandle = styled(({isDragging, ...props}) => <Icon {...props} />)`
  cursor: move;
  visibility: ${props => !props.isDragging && 'hidden'}; 
  color: ${props => props.isDragging ? props.theme.color : props.theme.colorGrayLight};
  &:hover {
    color: ${props => props.theme.color};
  }
  ${ParentComponent}:hover & {
    visibility: visible;
  }
`

The issue still remains when I move items between columns.

So this solution by @masonnl works only on the current column.

const style = snapshot.isDraggingOver ? {
  "pointer-events": "none"
} : {};

I guess that storing isDragging state globally for other columns is a way to go.

Can anybody help with a more simple solution?

Was this page helpful?
0 / 5 - 0 ratings