DEV Community

Cover image for Create To-do List using Vanilla JavaScript
Karan Developer
Karan Developer

Posted on • Updated on • Originally published at karankumar.hashnode.dev

Create To-do List using Vanilla JavaScript

It's a simple To-do app. As a beginner, creating these features like DOM manipulations, animations and dark theme feature was challenging for me. So let's see how I created this and what I've learned from it.

Prerequisite Knowledge

Basics of HTML, CSS and JS (specially DOM Manipulations)

What I've Learned
  • DOM Manipulation
  • Classlist
  • ChildNodes
  • Forms
  • Changing Themes

Let's Start

We will create this project step by step.
Features Planning

1. Brainstorming

First you have to plan the features of your to-do app. You can use any software to plan your project or just a pen and paper. I generally prefer to plan everything in Notion.

Features Planning


2. Sketching

Make a simple sketch of To-do app which contains all your decided features.

Sketching


3. Prototype

Make a prototype of your app using previous sketch. You can also follow these steps to design your app.

  • Make a color palette of 3 colors.
  • Choose the typeface.
  • Collect SVG icons
  • Start designing
  • Design the Dark theme

Xd Screenshot


4. Setup Project Environment

In this step, setup the directories and create files for your project.

Setup Environment


5. Create HTML structure

Open your index.html file and create the html structure. Don't forget to link your CSS and Js file with index.html.

Refrence code is given below.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>TODO :: By karan Kumar</title>

    <link rel="stylesheet" href="style.css" />
    <script src="script.js" defer></script>
</head>

<body>
    <div class="container task_list_empty">
        <header>
            <div class="theme_toogle">
                <button class="theme_toogle_btn"></button>
            </div>
            <span class="heading">My Day</span>
        </header>
        <section class="tasks">
            <ul id="tasksList"></ul>
        </section>
        <footer>
            <form id="new_task_form">
                <input type="text" name="new_task_input" id="new_task_input" placeholder="Create New Task" value="" />
                <button id="new_task_input_btn" type="submit"></button>
            </form>
        </footer>
    </div>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

6. Add CSS Styling

Open your style.css file to style the to-do app. Follow these steps to style your to-do.

  • Set root variables
  • Define container layouts
  • Set hover effects
  • Style input placeholder using pseudo classes.
  • Add Media queries
Refrence code is given below.
:root {
    --primary-color: white;
    --secondary-color: #1E1E1E;
    --text-color: black;
    --task-color: white;
    --footer-color: #1E1E1E;
    --theme-btn: url('assets/Dark-theme-btn.svg');
    --container-bg: url('./assets/Light-empty.svg');
    --complete-icon: url('assets/complete.svg');
    --filter: none;
    --theme-transition: 0s;

}

* {
    font-family: "Times New Roman";
    outline: none;
}

body {
    display: flex;
    min-height: 100vh;
    justify-content: center;
    align-items: center;
    overflow: hidden;

}

.container {
    position: relative;
    border: 4px var(--footer-color) solid;
    padding: 30px;
    display: flex;
    flex-direction: column;
    width: 300px;
    height: 80vh;
    border-radius: 20px;
    overflow: hidden;
    background: var(--primary-color);
    transition: var(--theme-transition);
}

header {
    display: flex;
    flex-direction: column;
}

.heading {
    font-weight: 900;
    color: var(--text-color);
}

.theme_toogle {
    text-align: right;
    margin-right: -15px;

}

.theme_toogle_btn {
    min-width: 30px;
    min-height: 30px;
    background-color: transparent;
    border: none;
    outline: none;
    background-image: var(--theme-btn);
    background-repeat: no-repeat;
    background-size: 80%;
    background-position: center;
    padding: 20px;
    cursor: pointer;
}

.theme_toogle_btn:hover {
    background-size: 85%;
    transition: 0.5s;
    transform: rotate(90deg);
}

.heading {
    font-size: 30px;
}

.tasks {
    margin: 20px 0px;
    overflow: hidden;
    padding-right: 15p;
}

#tasksList {
    padding: 0px;
}

.task_list_empty {
    transition: 0s;
    background-position: center;
    background-size: 50%;
    background-repeat: no-repeat;
    background-image: var(--container-bg);

}

.task_item {
    list-style-type: none;
    border: 1px var(--secondary-color) solid;
    padding: 10px;
    display: flex;
    flex-direction: row;
    align-items: center;
    border-radius: 7px;
    margin-bottom: 20px;
    background-color: var(--task-color);
    color: var(--text-color);
}

.task_item:hover {
    transition: 0.5s;
    /* border: 1px rgba(148, 148, 148, 0.63) solid; */
    cursor: pointer;
    background-color:rgba(226, 226, 226, 0.192);

}

.task_check_btn {
    width: 10px;
    height: 10px;
    margin-right: 16px;
    padding: 3px;
    border: 2px var(--secondary-color) solid;
    /* color: var(--primary-color); */
    background-position: center;
    background-size: contain;
    border-radius: 50%;
    border: 2px grey solid;
    cursor: pointer;
}

.task_check_btn:hover {
    background-image: url('assets/complete.svg');
    /* opacity: 0.5; */
    filter: var(--filter);

}

.task_bio {
    font-size: 18px;
}



.task-completed {
    transition: 0.5s;
    transform: scale(90%);
    text-decoration: line-through;
    color: rgb(150, 150, 150);
    opacity: 0;

}

footer {
    position: absolute;
    bottom: 0px;
    padding: 15px 10px;
    min-width: 100%;
    background-color: var(--footer-color);
    left: 0px;
    border: 5px var(--footer-color) solid;
}

footer form {
    display: flex;
    flex-direction: row;
    align-content: center;
}

#new_task_input {
    min-width: 250px;
    margin-right: 40px;
    font-size: 20px;
    color: white;
    background-color: transparent;
    border: none;
    border-bottom: 1px rgba(255, 255, 255, 0.267) solid;
}

#new_task_input::placeholder {
    color: rgba(255, 255, 255, 0.589);
    font-size: 20px;
    font-family: "Times New Roman";
}

#new_task_input_btn {
    width: 30px;
    height: 30px;
    background-color: transparent;
    border: none;
    background-image: url('./assets/new.svg');
    background-repeat: no-repeat;
    background-size: 80%;
    cursor: pointer;
}

.taskCompleted {
    visibility: hidden;
}

@media screen and (max-width : 600px) {

    body {
        margin: 0px;
        padding: 0px;
        align-items: flex-start;
        height: 100vh;
        background-color: var(--bg-color);

    }

    .theme_toogle {
        margin-top: 30px;

    }

    .container {
        border: none;
        border-radius: 0px;
        width: 100%;
        height: 93vh;
        padding: 0px 20px;
    }

    #new_task_input {
        margin-right: 20px;
    }
}

Enter fullscreen mode Exit fullscreen mode

7. Add JavaScript Functionality

Before starting any JS code, first you have to plan the working of your To-do App

Plan the working of to-do app

To-do Working

When user enter a new task in input and submit the form the task input value will go to a function , which creates a task element with checkbox using task input value. then add another function, which remove the task item when checkbox get checked.

Open your script.js file and style the to-do app. Follow these steps to add JS Functionality.

Refrence code is given below.
// Variables
var root = document.querySelector(':root')
var container = document.querySelector('.container');
var newTaskInput = document.getElementById('new_task_input')
var taskform = document.getElementById('new_task_form');
var tasksList = document.getElementById('tasksList');
var taskBtns = document.querySelectorAll('.task_check_btn');
var themeBtn = document.querySelector('.theme_toogle_btn');
// Do this when we submit the form
taskform.addEventListener('submit', function (e) {

    e.preventDefault();
    var newtaskInputValue = taskform.elements.new_task_input;


    addTask(newtaskInputValue.value)

    // Reset input value to empty
    newtaskInputValue.value = '';
    container.classList.remove('task_list_empty')


})

// To  add task in List
function addTask(newTask) {

    // Create li element and set its class
    const newTaskItem = document.createElement('li');
    newTaskItem.setAttribute('class', 'task_item');

    // Create checkbox  element and set its type and  class 

    const newCheckBtn = document.createElement('div');
    newCheckBtn.setAttribute('class', 'task_check_btn')

    // Create span  element and set its class and add new task input
    const newTaskBio = document.createElement('span');
    newTaskBio.setAttribute('class', 'task_bio')
    // Put value of input in it
    newTaskBio.innerText = newTask; // putting value of input in the li

    // append (insert) li tag in Ul
    tasksList.appendChild(newTaskItem)
    // append (insert) checkbox in li
    newTaskItem.appendChild(newCheckBtn)

    // append (insert) newtask in li
    newTaskItem.appendChild(newTaskBio)

    // Run this function when task is completed or checkbox is checked
    onTaskComplete(newCheckBtn)

}

// To remove the completed task
function onTaskComplete(btns) {

    btns.addEventListener('click', function (e) {
        var parent = e.toElement.parentElement;
        parent.classList.add('task-completed'); // To slide out the task to the right
        // Now we delete that tast which we have slided out
        setTimeout(() => {
            // Removing Parent Element of checkobx which is Li in 0.5 s
            parent.remove();
        }, 400);


        if (tasksList.childNodes.length == 1) {
            setTimeout(() => {
                container.classList.add('task_list_empty')

            }, 800);
        }

    })


}


// Dark mode

themeBtn.addEventListener('click', function () {


    var darkTheme = themeBtn.classList.toggle('dark')

    if (darkTheme) {

        root.style.setProperty('--theme-transition', '1s')
        root.style.setProperty('--primary-color', '#1E1E1E')
        root.style.setProperty('--secondary-color', '#3B3B3B')
        root.style.setProperty('--text-color', '#EAEAEA')
        root.style.setProperty('--task-color', '#3B3B3B')
        root.style.setProperty('--footer-color', '#1E1E1E')
        root.style.setProperty('--theme-btn', `url('assets/Light-theme-btn.svg')`)
        root.style.setProperty('--container-bg', `url('./assets/Dark-empty.svg')`)
        root.style.setProperty('--filter', 'invert()')

    } else {
        root.style.setProperty('transition', '1s')
        root.style.setProperty('--primary-color', 'white')
        root.style.setProperty('--secondary-color', '#1E1E1E')
        root.style.setProperty('--text-color', 'black')
        root.style.setProperty('--task-color', 'white')
        root.style.setProperty('--footer-color', '#1E1E1E')
        root.style.setProperty('--theme-btn', `url('assets/Dark-theme-btn.svg')`)
        root.style.setProperty('--container-bg', `url('./assets/Light-empty.svg')`)
    }
})

Enter fullscreen mode Exit fullscreen mode

View Demo

Project Demo

Edit To-do List

Source Code

GitHub logo thekarandeveloper / To-Do-List

A Todo List built using HTML , CSS and Vanilla JS


Find Me on Instagram

@karancodes Instagram Profile

Top comments (11)

Collapse
 
barelyhuman profile image
Reaper

That's a well planned project even if it's something you can normally just start coding with. Noice.
here's an alternative design if you'd like to check it out.
old.todo.reaper.im/
todo.reaper.im/

Collapse
 
atchafalaya profile image
James Proctor

Very nice! Your dark mode/light mode button seems to hang on clicking, going from dark to light it pauses at a full circle before going to light mode.

Collapse
 
barelyhuman profile image
Reaper • Edited

That’s actually the system theme mode.

If your OS is on dark, it’ll be dark, if its on light it’ll be light, else you can choose with the other 2 toggle states

Thread Thread
 
atchafalaya profile image
James Proctor

Oh, now I see. I like it very much! I notice that when I scroll down, the task list moves the first task underneath the entry box and therefore out of sight. Again, really like your to-do list, especially the share function.

Thread Thread
 
barelyhuman profile image
Reaper

Thanks :)

Collapse
 
dannyengelman profile image
Danny Engelman • Edited

Very good blog!
One minor suggestion, modern append is more powerful:

newTaskItem.appendChild(newCheckBtn)
newTaskItem.appendChild(newTaskBio)
Enter fullscreen mode Exit fullscreen mode

can be written as:

newTaskItem.append( newCheckBtn , newTaskBio )
Enter fullscreen mode Exit fullscreen mode

Append is available in every modern browser (not IE11)

See: developer.mozilla.org/en-US/docs/W...

Collapse
 
bigt1305 profile image
Anthony Hoss

Thank you for describing your whole process on seeing the project through; it helps than just a mere tutorial, really awesome end product!!:)

Collapse
 
stormyfiend profile image
Mrvn

cool what is the name of your theme in vscode

Collapse
 
karandeveloper profile image
Karan Developer
Collapse
 
devfranpr profile image
DevFranPR

What a well structured process to make an aplication 👍

Collapse
 
atchafalaya profile image
James Proctor

It's a very beautiful design, but I can't seem to scroll down if I add enough tasks to go below the bottom of the page. Am I missing something?