nearly all websites need a little bit of
drag-and-drop functionality so in this
video I'm going to show you how to build
a really simple sortable drag-and-drop
system using just HTML CSS and vanilla
JavaScript so let's get started now but
before we get started I want to tell you
how you can get an entire year of
hosting for free by using today's video
sponsor atlanticnet hosting atlanticnet
is giving you an entire year of free
hosting on their servers and these are
powerful servers that are more powerful
than the servers I host my own website
on so if you go to atlanticnet linked in
the description below and use the code
kyle when you sign up you're gonna get
an entire year of free hosting as well
as an additional $50 of credit to use
however you see fit
so make sure you check that out because
this is a great deal and you're not
gonna find this much free hosting
anywhere else welcome back to web dev
simplified my name is Kyle and my job is
to simplify the web for you so you can
start building your dream project sooner
so if that sounds interesting make sure
you subscribe to the channel for more
videos just like this now on the right I
have the final version of the product
we're gonna be building as you can see
it's very simply styled but we can
select any element in these lists and we
can drag it around and you can see we
get this nice little ghost image
appearing on our cursor as well as an
indicator of where the item is going to
be placed and then when we release the
item it's going to be put exactly where
we want it and we can drag items between
any of these containers back up to the
container and it's really flexible and
the amount of code to create this is
actually pretty small so in order to get
started I just have an empty project
open up and Visual Studio code we're
gonna create an index file called
index.html we're gonna have a style
sheet called styles dot CSS just for
these really basic styles and then we're
also going to have a script J's file for
all of our different JavaScript and now
in our index.html
we just hit exclamation point hit tab or
enter it's going to fill out all of this
bully of the plate for us and we can
come in here and link our style sheet
which is called styles.css we can also
linked our
javascript which is just going to be
called script a s and we're gonna make
sure we give this the defer attribute so
it loads after our HTML is done now
inside of our HTML we're gonna build up
an initial container that looks like
this where we have one two in the top
and three four in the bottom so we're
gonna have a div with the class of
container which is going to be this
black box so we're gonna have two of
those divs and then inside of these divs
we're going to have a bunch of different
P tags and these P tags are going to be
one two three or four so we're gonna
give them a class of draggable so that
we know that these are draggable
elements and then in order to make
something draggable using javascript
there's an attribute called draggable
and we just need to set this to true so
if we set this draggable attribute to
true
we're already partway there into making
elements on our page draggable now let's
just put the text of one in here copy
this down and have another one for two
and then we're gonna copy these into our
bottom container so that we have a three
and a four and we can save that and if
we just right-click this and open with
live server which is an extension for
visual studio code you can download you
can see we have one two three and four
so now in order to style these properly
let's just open up our style sheet and
do a few really minor styles so the
first thing I want to do is select our
body and remove the margin so that we
can get our black container pushed right
up against the side of our screen and
then we're gonna style our container to
give it that black style look so we're
gonna say a background color here so
background color we're gonna make this
background color three three three it's
just gonna give us this nice grayish
color as you can see over here and then
we want to give it a little bit of
padding so we'll say one rem and we'll
give it a little margin on the top of
one REM just to space these black
containers out from one another and now
we can select our different draggable
elements and inside of our draggable
elements we're gonna give them a little
padding on their own a background color
which is going to be white and if we
save you can already see that starting
to look good let's just give them a
little bit of a border I'll say one
pixel solid black just to give them a
little bit of appearance like that and
then lastly to get to this nice little
moveable cursor what we can do is just
change our cursor over here
to be move and then we hover over any of
these we get that nice little movable
looking cursor and as you can see
already we can drag these elements by
just clicking on them and that's because
of that draggable property but it
doesn't matter where we drag them
nothing's gonna happen they're not
actually going to move so we're gonna
need JavaScript to set that up so now
inside of our script is let's actually
just select the different elements we're
going to need the first thing that we're
gonna need is to get the different
elements we can drag all these different
P tags so we can just get an element
called draggable x' which is going to be
equal to document query selector of all
and we know that these all have a class
of draggable so we can just use that
draggable class next we're going to need
to get our different containers because
the containers are where we're able to
drop our different elements so when
you're doing drag-and-drop with HTML
one's JavaScript you need to know what
your draggable elements are in our case
these different P tags and you also need
to know where you can drop these
elements which are these black
rectangles in our scenario so we need to
get those containers so we can just do
another document that query selector all
and this one we're going to get for that
dot container class which we already
know is going to be these black
containers so now once we have those we
can set up all of our event listeners so
let's do our draggable event listeners
first we can say draggable x' dot for
each so that we can loop through each of
our draggable x' and when we loop
through each one of these we want to add
some event listeners so we can say
draggable dot add event listener and the
first event listener that we want to
listen to is what happens as soon as we
start dragging our element and this is
going to be the drag start event and
this gets fired as soon as we start
dragging an element and I can prove that
by just saying console dot log dragged
start and now if we just inspect this
real quick drag this over so we can see
our console and if I start to drag this
you're gonna see we get that drag start
printed out every time we start to drag
any of our different P tags so this
happens only when we first initially
click and start our dragging and it
won't fire again at all until we start a
new drag so that's really useful
so with that drag start what we can do
is just apply a class to tell us that we
are currently dragging this element
that way we can get this nice little
opaque style where we have this element
it's a little bit different color than
the rest of the elements so in order to
do that let's just say our draggable all
we want to do is we want to come in here
get our class list we want to add a
class and we want to add a class called
dragging and then in our Styles we can
select any draggable that has that
dragging class and we can just change
the opacity down to 0.5 and now when we
start our drag you can see that that
opacity changes to 0.5 but when we
release our drag it still stays at 0.5
so we need to set up another event
listener on our draggable and this event
listener is going to be one our drag
stops so we can just come in here and
say drag end which is the same thing as
drag start but it calls as soon as we
let go of the element and inside of here
we want to just remove that class list
so we can say class list remove that
dragging in class and now when we hover
this you see it gets that nice opaque
class and when we release it you can see
that class goes away and that's because
these drag start and drag and events so
now we have all of that nice stuff for
dragging our element around changing the
class so it changes its opacity but what
we need to do next is actually be able
to move this element around inside the
container as well as drop it in other
containers so we need to loop through
our containers in order to determine how
our dragging works for when we're
dropping our element as well as how when
we're moving our element around so we
can just say containers for each
container whoops there we go and inside
it here we need to listen to an event
called drag over so we can say container
dot add event listener and this one is
dragged over and then we can just run
this function and just just show you
what's happening let's just console dot
log inside of here drag over and again
if we inspect our page bring over that
console we can see that as soon as we
start dragging an element over our
container it's printing out drag over
all the time just repeatedly printing
that over and whenever we go outside of
our container you see that drag over
stops but anytime we're in a container
we get that drag over function being ran
so this function is going to be really
useful since we can actually determine
which element we're over top of as well
as if we're not over an element at all
and it's gonna constantly run every
single time we move our mouse so in
order to actually take advantage of that
what we need to do in here is as you can
see over here we're determining what
position our element is inside of the
container based on our mouse and we're
also determining which element is inside
of so if it's in the second container or
this first container so we need to do
all of that logic inside of this drag
over function the easy way to do this
for now is to ignore all of this sorting
and just determine if we're inside
container one or inside container two so
in order to do that what we want to do
in here is get our dragging element
essentially get the element we're
currently dragging and that's pretty
easy to do
we can just say Const draggable which is
going to be our current draggable is
equal to document diet query selector
and we know that only one element will
have the dragging class at a given time
since is the element we're currently
dragging so that'll be this draggable
element here whichever one we're
currently dragging and then all we want
to do is append it to whatever container
we're inside of so we can say container
dot append child we could just pass in
our draggable now when we hover this you
see if we're inside of container one
it's gonna add it to the bottom of
container one and if we go down to
container two it's gonna add it to the
bottom of container two and when we
release you can see it stays inside that
container
same thing with up here and down here
the one interesting thing you notice is
that our cursor has the do not allow
simple you see that kind of circle with
the line through it in order to remove
that what we need to do is inside of our
event we actually need to take our event
object and we need to just call prevent
default because by default dropping
inside of an element is disabled so in
order to enable dropping we need to say
a dot prevent default and this is going
to change our cursor to have a curse
that says we are able to drop inside of
here as you can see when we're outside
we get the do not allow cursor and when
we're inside we get this drop is allowed
cursor so now with that taken care of
our next step is to determine the order
of our elements based on where our mouse
position is instead of just determining
what container were in we need to figure
out which element we're actually placing
this in between whether it's in between
three and four above three below four
inside this container and so on so let's
just create a simple function and inside
of this function we're gonna call it get
dry
after element and this is going to take
in our container as well as the wide
position of our mouse so what this
function is going to do it's going to
determine our mouse position when we're
dragging our element and it's going to
return which ever element our mouse
position is directly after so in this
case when we're dragging our one you can
see our mouse is right above number four
so this get dragged actor would return
this fourth element so we know to insert
above number four if our mouse was up
here it would return number three since
we're close to two number three and
right above it and if we are for some
reason below all of our elements it
would return nothing because it just
knows we need to append to the end of
our container
so let's actually write out this
function and the first thing we need to
do is determine all of the elements
inside of the container that we are
currently hovering over which is this
container we pass in so we can just come
in here and say container dot queries
selector all and we want to get all of
our draggable elements so we can
determine where we're gonna place this
in our list but one problem with this is
when we're hovering this one over top of
this you can see we have elements three
and four but also the element we're
dragging number one is also in this
container so we want to ignore
everything that we're currently dragging
so to do that we can just use the knot
selector and just say dot dragging which
is the current element we're dragging so
this will get every draggable that we're
not currently dragging so essentially if
we're dragging element one it'll only
get element three and four and not the
one that we're dragging and now that we
have this information we want to convert
this to an array so that we can actually
do array operations on it because query
selector all doesn't return an array so
in order to do that we can just use the
spread operator to spread this out into
a new array and with this we can just
set this to a variable which we're just
gonna call draggable elements just like
that so this is all of our draggable
elements inside of our container and now
we want to call a function on draggable
elements called reduce and what reduce
is going to do is is essentially going
to loop through this element list of
dragged ball elements and we're going to
determine which single element is the
one that is directly after our mouse
cursor based on this y position that we
pass in and we can get this Y position
from our event so actually let's just
say
const after element up here which is
going to be the return of this get drag
after element we're gonna set that equal
to calling that function passing in our
current container and then the e dot
client why this is just going to be the
y position of our mouse on the screen
now this reduce function if you're not
familiar with it I have a video covering
it which you can find in the cards in
the description down below
but essentially this is going to take a
function and then it is also going to
take a second parameter which is
essentially the initial value of our
reduce so this function is going to take
in two parameters the first parameter is
going to be the value we're reducing
down to so we're gonna call this closest
because this is going to be the element
that we're closest to that is directly
after our mouse cursor and then the next
parameter is going to be each one of
these draggable elements we'll just call
this child because each one of them are
a child of the container were inside of
so for each one of our draggable
elements this function is going to be
called and whatever this function
returns is what is this closest section
inside of this function and then this
second parameter of reduce is just the
initial value of closest so what we want
to figure out inside of this function is
which element is directly after our
mouse cursor so to keep track of that we
need to figure out the offset between
our cursor and the element that comes
directly after it as well as the element
that's directly after it so initially we
just want to have a value which has an
offset which is going to be a really
really large number we want it to be
essentially infinitely far away from our
mouse cursor or so we'll say number dot
infinite and we can do positive infinity
here so number dot positive infinity
essentially it's going to be the largest
number possible so every single number
is going to be smaller than that and
this is just so that initially we have a
number that is way too large and every
single other element in the list is
going to be closer than this number not
positive infinity now inside of this
function we need to determine the actual
position of the elements on our screen
in relation to our mouse so we can get
what's called the bounding box by just
calling here child get bounding client
rect which is a function and this is
going to give us a rectangle for our box
and let's just log this out real quick
so we can
console dot log box just to see exactly
what's going on inside of this function
and if we come over here inspect our
page go to the console and we drag one
of these elements you'll notice
nothing's actually being logged out
which means we probably have something
wrong in our code so if we go over here
and check our code we can just see we
got draggable elements getting that from
our query selector and you notice I
forgot to put a period here for our
class selector for draggable so when I
add that in once again inspect our page
over our console and if we drag this you
now see we're getting a bunch of things
printed out these are the rectangles of
our children we have the x position the
y position as well as width height and
then the top right bottom hand left hand
position so right and left are going to
be x and top and bottom are going to be
in Y so for our use case we essentially
want to measure from the middle of our
box so to do that we can just take the
top and we could subtract out half of
the height of our box and that's going
to give us the dead center of our box so
let's start doing that now so we have
our box the next thing we want to do is
get the offset this is essentially going
to be the distance between the center of
our box and our actual mouse cursor so
we can say that our offset here is going
to be equal to our Y position which is
our mouse Y position and we want to
subtract our box top so this is the top
of our box and then since we want the
middle of our box we again need to
subtract out our box height and we need
to divide that by 2 so half the height
of our box will put us in the dead
center of each one of our boxes and now
if we print out this offset and then
just come over here
we'll inspect our page make sure that we
go to our console and then inside of
here if we drag number 2 you can see
that when we're above our elements we
get negative numbers when we're below an
element we get a positive number which
is why we have one positive and one
negative number and we'll more below all
of our elements you can see every number
is positive so essentially when we're
below an element our numbers are
positive when we're above an element our
numbers are negative so we only care
about offsets that are negative because
that means that we're currently hovering
above that element so let's close out of
this and we know for a fact we only want
to be concerned with offsets that are
less than zero essentially we're above
the element that we're hovering over
because if the offset is positive then
that means that we're no longer
hovering over that element and we are
now below that element so now we know we
only want offsets that are less than
zero but we also want the offset that is
the closest to zero because essentially
if we're as close as possible to zero
then that means we are barely having our
cursor above that element so if we were
for example hovering our cursor right
here we're barely above element three so
we know that this is going to be close
to zero and since we're actually basing
this on half right in the dead center
here we know if we hover here right
above the center of element three we
know that this is going to be nearly
zero so we always want to find the
offset that is less than zero but as
close to zero as possible so in order to
determine which element is our new
closest element we can say if our offset
is less than zero and our offset is
greater than our closest dot offset
which in our case down here is infinity
to start with so if our offset is closer
than our closest offset essentially it's
closer to zero then whatever offset we
currently have then we know that this is
going to be our new closest element so
we can just come in here and we can
return an object which is going to have
an offset which is going to be our
current offset and it's also going to
have an element oops
element which is going to be our child
which is just the current element that
we're iterating through and one thing to
know here is since we always are
checking for our offset being greater
than our closest offset and our initial
closest offset is positive infinity we
need this to be negative infinity
because we always want to make sure that
this first initial offset is always
going to be the smallest number so that
way any offset is always initially
greater than our default offset so now
we can have an else statement instead of
here
so essentially else if our offset is
either greater than zero or it's not
larger than the closest offset that we
previously had we just want to return
our closest that we have for now we can
close off that if just like that and
let's make sure that we return this here
and now we can just come up here do a
console dot log of our after element and
make sure we return whatever we're
reducing so essentially return this
entire reduce function and we should see
this after element being whatever our
mouse cursor is directly above but to
make sure we're only getting the element
here and
the offset and the element as you can
see here we're just gonna return the
element that we get from our reduce
function down here so now if we save
this inspect our elements over here and
go to our console you can see that when
we hover this element for example when
we're above r2 you can see that we're
getting our draggable being returned for
- as you can see over here and you're
also seeing this offset being printed we
just need to remove this log for that
offset and now we can go back and
inspect this go to our console and let's
do another drag here we can see if we
dragged our three when it's above four
we get four being printed as our number
as you can see we have four right here
and if we drag this up here above our
one we get one being printed above two
we get two being printed and if we drag
it above nothing we get undefined to be
imprinted so that we can determine
whether or above something for example
one or two or four above nothing and we
know we need to append to the end of our
list so now what we can do is we can use
that inside of this function here to
determine where we're going to put our
element so we can say if our after
element equals null so exam for example
we're not above anything then we can
just do what we did before we can append
our child to the end of the list and we
can just move our draggable up to here
so now this will currently work if our
after element is not anything so if we
drag one and we're not above anything
it'll come to the bottom of our list as
you can see here once we go below
everything it goes to the bottom of our
list so that is working the next thing
we have to do is to actually determine
which element we're inserting before so
to do that we can just put in an else
here and we can say container dot insert
before and here we're going to pass in
the new child which in our case is our
draggable and then whichever element
we're inserting before which is our
after element and now we can save and if
we drag one below - it'll go below to
above - it'll go above to come down here
and above three it'll be above three
same thing with four same thing if it's
below and we'll we let go it'll stay in
that position so now we can move our
elements around freely and put them
wherever we want inside of our
containers and that's all there is to
creating this simple drag-and-drop
sortable list if you enjoyed this video
make sure to check out my other videos
linked over here and subscribe to the
channel for more videos just like this
one thank you very much for watching and
have a good day