In this post, I will show you a simple implementation of drag and drop with React. It uses HTML API for drag and drop.
We will have a component named Card
and a hoc (high order component) named withDraggable
which will implement the drag and drop logic.
Let's begin by looking at our Card
component:
import React from 'react'
import styled from 'styled-components'
export const Card=
({name,img,...rest})=>
{
const Card=styled.div`
background-color: antiquewhite;
margin: 5px 5px;
padding: 40px;
border-radius: 8px;
width: 186px;
height:250px;
text-align: center;
box-shadow: 0 16px 32px -16px #B0BEC5;
border: 4px groove rgb(166,55,198);
cursor:pointer;
float:left;
img {
width: 100%;
height:100%;
}
h2 {
margin-top: 8px;
font-weight: 900;
color: #4CAF50;
}
`
const el=
<Card {...rest}>
<img
src={img}
alt="Profile image" draggable='false'/>
<h2>{name}</h2>
</Card>
return el
}
This is how this component look like on the screen (browser):
So we have this component Card
per se it is not draggable. Now let's see drag and drop implementation, that's it, let's see withDraggable
hoc:
import React from 'react'
import styled from 'styled-components'
export default
C=>({empty,...props})=>
{
const onDragOver=e=>
{
e.preventDefault()
const element=e.currentTarget
element.style.backgroundColor='purple'
}
const onDragLeave=e=>
{
const element=e.currentTarget
element.style.backgroundColor='white'
}
const onDrop=e=>
{
const insertAfter=(newNode,referenceNode)=> {
referenceNode.parentNode.insertBefore(newNode,referenceNode.nextSibling)
}
const dropZone=e.currentTarget
dropZone.style.backgroundColor='white'
const id=e.dataTransfer.getData('text')
const draggableElement=document.getElementById(id)
insertAfter(draggableElement.parentNode,dropZone.parentNode)
e.dataTransfer.clearData()
}
const onDropLeft=e=>
{
const insertBefore=(newNode,referenceNode)=> {
referenceNode.parentNode.insertBefore(newNode,referenceNode)
}
const dropZone=e.currentTarget
dropZone.style.backgroundColor='white'
const id=e.dataTransfer.getData('text')
const draggableElement=document.getElementById(id)
insertBefore(draggableElement.parentNode,dropZone.parentNode)
e.dataTransfer.clearData()
}
const onDragStart=
e=>
{
const element=e.currentTarget
e.dataTransfer.setData('text',e.target.id)
}
const DroppableCardZone=styled.div`
width:10px;
margin: 10px 0px;
border-radius:3px;
`
const Container=styled.div`
float:left;
display:flex;
`
const el=
<Container>
<DroppableCardZone onDragOver={onDragOver} onDrop={onDropLeft} onDragLeave={onDragLeave}/>
<C {...props} draggable='true' onDragStart={onDragStart}/>
<DroppableCardZone onDragOver={onDragOver} onDrop={onDrop} onDragLeave={onDragLeave}/>
</Container>
return el
}
As you can see in this file, we first make C
component draggable with the property draggable='true'
. All this is HTML API.
Then we pay attention to onDragOver
event handler. The first line of code which is e.preventDefault()
it is meant to allow for a dropping area (the default it is not to allow it). Then we change style so people (users) can see where to drop the dragged element.
Then we look at onDrop
event handler. There are two handlers for this event, onDrop
and onDropLeft
. The first one is for dropping to the right and the second one for dropping to the left. We will comment on only one of them (the other one it's almost the same). What we do in this event handler it is first to change back the style of the dropping zone which was changed on the onDragOver
event handler (dropZone.style.backgroundColor='white'
). Then we get the id
of the dragged element (const id=e.dataTransfer.getData('text')
). dataTransfer
is part of the HTML API. Then we get the element itself (const draggableElement=document.getElementById(id)
). Finally we insert the DraggableCard
after the droppable zone (insertAfter(draggableElement.parentNode,dropZone.parentNode)
).
It only rests us to see the onDragStart
event handler. What we do on this event handler is this: e.dataTransfer.setData('text',e.target.id)
, that's it, we use the HTML API for drag and drop to set the id
of the dragged element.
Let's look at the App
component:
import React from 'react'
import * as S from '../../styled/styled'
import withDraggable from '../withDraggable/withDraggable'
import {Card} from '../card/card'
import imgOne from '../../images/one.png'
import imgTwo from '../../images/two.png'
import imgThree from '../../images/three.png'
import imgFour from '../../images/four.png'
import imgFive from '../../images/five.png'
export const App=
()=>
{
const DraggableCard=withDraggable(Card)
const el=
<S.Div>
<DraggableCard
img={imgOne}
name={"roger"}
id='card-1'/>
<DraggableCard
img={imgTwo}
name={"gomez"}
id='card-2'/>
<DraggableCard
img={imgThree}
name={"alejandro"}
id='card-3'/>
<DraggableCard
img={imgFour}
name={"gonzalez"}
id='card-4'/>
<DraggableCard
img={imgFive}
name={"alberto"}
id='card-5'/>
</S.Div>
return el
}
So that's it. We have developed a hoc (high order component) which implements the logic for drag and drop in React, and applied to a component Card
we had. 🍺
Top comments (1)
Is there a demo, or a repo where we can reference where withDraggable and the images come from