I have a problem with scrolling list on mobile after I put DnD on list elements.
I have a list of cards. And I want every card to be draggable.
I use touchAction: 'none', without it there was a problem to scroll without dragging: the card which was under a finger while scrolling was also dragging. Now dragging works but scrolling is not.
This is my code:
export const CardComponent = forwardRef((props: CardComponentProps) => {
const { style, attributes, listeners, setNodeRef } = props;
const onCardClick = () => {};
return (
<div style={style} {...attributes} {...listeners} ref={setNodeRef as React.ForwardedRef<HTMLDivElement>}>
<Card onClick={onCardClick}>{/* ...content */}</Card>
</div>
);
});
export const SortableItem = ({ id }: SortableItemProps) => {
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id });
const style = {
transform: CSS.Translate.toString(transform),
transition,
touchAction: 'none',
zIndex: isDragging && 35,
};
return (
<Wrapper className="mt-5">
<CardComponent setNodeRef={setNodeRef} style={style} attributes={attributes} listeners={listeners} />
</Wrapper>
);
};
export const Dropable = ({ lists, handleDragEnd }: DropableProps) => {
const sensors = useSensors(
useSensor(PointerSensor, {
activationConstraint: {
distance: 8,
},
}),
useSensor(KeyboardSensor, {
coordinateGetter: sortableKeyboardCoordinates,
}),
);
return (
<Wrapper>
{lists && (
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={handleDragEnd}
modifiers={[restrictToVerticalAxis, restrictToFirstScrollableAncestor]}
>
<SortableContext items={lists?.map((item) => item.Id as string)} strategy={verticalListSortingStrategy}>
{lists?.map(({ Id: id }) => {
return <SortableItem key={id} id={id as string} />;
})}
</SortableContext>
</DndContext>
)}
</Wrapper>
);
};
I have tried to put dragging button and put touchAction: 'none' only on the button but it was not accepted by reviewer. The card has to be without the button coz it's to small to fit the button.
You need to do modificate your sensors. Remove PointerSensor and use MouseSensor and TouchSensor and put delay in TouchSensor. Also remove touchAction: 'none'.
Like this:
const sensors = useSensors(
useSensor(MouseSensor, {
activationConstraint: {
distance: 8,
},
}),
useSensor(TouchSensor, {
activationConstraint: {
delay: 300,
tolerance: 8,
},
}),
useSensor(KeyboardSensor, {
coordinateGetter: sortableKeyboardCoordinates,
}),
);
Read more here
"If the above recommendations are not suitable for your use-case, we recommend that you use both the Mouse and Touch sensors instead, as Touch events do not suffer the same limitations as Pointer events, and it is possible to prevent the page from scrolling in touchmove events."
And here