≡ Menu

The To-Do List is the “Hello World” of web applications—and for good reason!

It teaches you the essential flow of modern web development: handling user input, manipulating the Document Object Model (DOM), and styling user feedback.

In this tutorial, we will build a functional, persistent To-Do list using only HTML, CSS, and vanilla JavaScript.

🛠️ Prerequisites

 

  • A basic understanding of HTML tags and CSS properties.

  • A text editor (like VS Code).

  • A web browser.

Let’s start by creating three files: index.html, style.css, and script.js.

Step 1: HTML Structure (The Skeleton)

 

The HTML sets up the basic layout: a header, an input area for new tasks, and an unordered list (<ul>) to hold the tasks. We use IDs to easily target these elements later with JavaScript.

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JS To-Do List</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <h1>My Task List</h1>
        <div class="input-area">
            <input type="text" id="task-input" placeholder="Enter a new task...">
            <button id="add-button">Add Task</button>
        </div>
        
        <ul id="todo-list">
            </ul>
    </div>

    <script src="script.js"></script>
</body>
</html>

Step 2: CSS Styling (The Look)

 

We will use simple CSS to make the application clean, centered, and visually indicate completed tasks.

CSS:

/* style.css */
body {
    font-family: Arial, sans-serif;
    background-color: #f4f4f9;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    margin: 0;
}

.container {
    background-color: #fff;
    padding: 30px;
    border-radius: 8px;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    width: 100%;
    max-width: 450px;
}

/* --- Input Area Styling --- */
.input-area {
    display: flex;
    margin-bottom: 20px;
}

#task-input {
    flex-grow: 1;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 4px 0 0 4px; /* Rounded left corners */
}

#add-button {
    background-color: #007bff;
    color: white;
    border: none;
    padding: 10px 15px;
    border-radius: 0 4px 4px 0; /* Rounded right corners */
    cursor: pointer;
    transition: background-color 0.2s;
}

#add-button:hover {
    background-color: #0056b3;
}

/* --- List Styling --- */
#todo-list {
    list-style: none;
    padding: 0;
}

#todo-list li {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px;
    margin-bottom: 8px;
    background-color: #eee;
    border-radius: 4px;
    cursor: pointer;
    transition: background-color 0.2s;
}

/* Style for completed tasks */
.completed {
    text-decoration: line-through;
    color: #888;
    background-color: #d9d9d9 !important;
}

/* --- Delete Button Styling --- */
.delete-btn {
    color: #ff4d4d;
    font-weight: bold;
    margin-left: 15px;
    cursor: pointer;
}

Step 3: JavaScript Logic (The Brain)

 

Now for the core logic. We need functions to add a task, toggle its completion status, and delete it.

3.1 Setup & Element Selection

 

We start by selecting the HTML elements we need to interact with.

JavaScript:

// script.js
const taskInput = document.getElementById('task-input');
const addButton = document.getElementById('add-button');
const todoList = document.getElementById('todo-list');

// Attach the event listener to the Add button
addButton.addEventListener('click', addTask);
// Also allow adding tasks by pressing 'Enter'
taskInput.addEventListener('keypress', function(e) {
    if (e.key === 'Enter') {
        addTask();
    }
});

3.2 The addTask() Function

 

This function handles creating the new list item element and inserting it into the DOM.

JavaScript:

// script.js (continued)

function addTask() {
    const taskText = taskInput.value.trim();

    // 1. Basic validation: Don't add empty tasks
    if (taskText === "") {
        alert("Please enter a task!");
        return;
    }

    // 2. Create the list item (li)
    const listItem = document.createElement('li');
    listItem.textContent = taskText;

    // 3. Create the delete button (span)
    const deleteBtn = document.createElement('span');
    deleteBtn.textContent = 'X';
    deleteBtn.classList.add('delete-btn');

    // 4. Attach event listeners to the new item

    // Click on the task itself to mark complete/incomplete
    listItem.addEventListener('click', function() {
        listItem.classList.toggle('completed');
    });

    // Click on the 'X' to delete the task
    deleteBtn.addEventListener('click', function(e) {
        // Stop the 'completed' toggle from firing when clicking delete
        e.stopPropagation(); 
        listItem.remove();
    });

    // 5. Assemble and append
    listItem.appendChild(deleteBtn);
    todoList.appendChild(listItem);

    // 6. Clear the input field for the next task
    taskInput.value = '';
}

Bonus Step: Data Persistence (Never Lose Your List!)

 

To prevent the list from disappearing when the user refreshes the page, we use the browser’s localStorage.

3.3 Adding Storage Logic

 

Wrap the previous logic in functions that also interact with localStorage.

  1. Modify addTask to also save to storage.

  2. Create saveTasks to update storage every time.

  3. Create loadTasks to rebuild the list when the page loads.

(Since this involves slightly more complex state management, I’ll stop here to keep the post brief, but this is a fantastic follow-up tutorial!)


Wrap-up

Congratulations! You now have a fully functional To-Do List application. This project demonstrated the core skills of front-end development:

  • HTML: Creating the basic page structure.

  • CSS: Styling for usability and aesthetics.

  • JavaScript: Dynamically creating elements (createElement), handling user events (addEventListener), and modifying the DOM (appendChild, toggle, remove).

Useful links below:

Let me & my team build you a money making website/blog for your business https://bit.ly/tnrwebsite_service

Get Bluehost hosting for as little as $1.99/month (save 75%)…https://bit.ly/3C1fZd2

Best email marketing automation solution on the market! http://www.aweber.com/?373860

Build high converting sales funnels with a few simple clicks of your mouse! https://bit.ly/484YV29

Join my Patreon for one-on-one coaching and help with your coding…https://www.patreon.com/c/TyronneRatcliff

Buy me a coffee ☕️https://buymeacoffee.com/tyronneratcliff

{ 0 comments }

If you’ve spent any time working with JavaScript, you know that arrays are the bedrock of data handling. But for too long, many developers have relied on the verbose for loop to process array data.

Modern JavaScript offers a much cleaner, more expressive, and more powerful way to transform data: the trio of higher-order array methods: map(), filter(), and reduce().

Mastering these methods is a key step toward writing more functional, readable, and professional JavaScript code.


1. The Setup: What Are Higher-Order Functions?

 

Before we dive in, let’s understand why these methods are so special.

A higher-order function is simply a function that does one (or both) of the following:

  1. Takes one or more functions as arguments (the callback function).

  2. Returns a function as its result.

map, filter, and reduce are all higher-order array functions because they take a callback function (a function you write) and apply it to every element in the array.


2. 🗺️ Map: The Transformer

 

The map() method is your tool for transformation. Its job is to take an array, perform an operation on every element, and return a new array of the exact same length.

Key takeaway: map() always returns a new array with the same number of elements.

The Use Case

 

Use map() when you want to convert an array of one type of data into an array of another type of data.

Example: Converting Prices

 

Imagine you have an array of product prices and you need to calculate the price including a 10% sales tax.

const originalPrices = [100, 25, 499, 50];

const pricesWithTax = originalPrices.map(price => {
  const tax = price * 0.10;
  return price + tax;
});

console.log(pricesWithTax);
// Output: [110, 27.5, 548.9, 55]

️ How it Works

 

The callback function inside map() takes three arguments (though you rarely use more than the first two):

  1. element: The current element being processed.

  2. index: The index of the current element.

  3. array: The array map was called upon.


3. ✂️ Filter: The Selector

 

The filter() method is your tool for selection. Its job is to look at every element in an array and decide whether to keep it or discard it. It returns a new array containing only the elements that meet a specified condition.

Key takeaway: filter() returns a new array that is the same length or shorter than the original.

The Use Case

 

Use filter() when you need to narrow down a list based on a logical test.

Example: Finding High-Rated Books

 

If you have an array of book objects and you only want to see the ones with a rating of 4.5 or higher:

JavaScript:

const books = [
  { title: 'Book A', rating: 4.8 },
  { title: 'Book B', rating: 3.2 },
  { title: 'Book C', rating: 4.6 }
];

const highRatedBooks = books.filter(book => {
  return book.rating >= 4.5;
});

console.log(highRatedBooks);
/*
Output: [
  { title: 'Book A', rating: 4.8 },
  { title: 'Book C', rating: 4.6 }
]
*/

️ How it Works

 

The callback function inside filter() must return a Boolean value (true or false).

  • If the callback returns true, the element is kept in the new array.

  • If the callback returns false, the element is discarded.


4. 🧮 Reduce: The Aggregator

 

The reduce() method is the most versatile and often the most confusing of the trio. Its job is to take an array and reduce it down to a single value. This value could be a number, a string, an object, or even another array.

Key takeaway: reduce() consolidates the entire array into a single result.

The Use Case

 

Use reduce() when you need to calculate a sum, count items, or flatten a complex array structure.

Example: Calculating a Total Sum

 

To find the grand total of the prices in an array:

JavaScript:

const prices = [100, 25, 499, 50];

const totalSum = prices.reduce((accumulator, currentValue) => {
  return accumulator + currentValue;
}, 0); // <-- The initial value for the accumulator

console.log(totalSum);
// Output: 674

️ How it Works

 

The reduce() callback takes two crucial arguments:

  1. accumulator: This is the running total or the value returned from the previous call to the function.

  2. currentValue: The current element being processed.

It also takes an optional second argument outside the callback: the initial value. This is the starting value of the accumulator. In the example above, we started the sum at 0.


5. 🤯 Chaining the Power

 

The real magic happens when you chain these methods together. Because map() and filter() both return new arrays, you can call another array method immediately after them.

Example: Filtering, then Mapping

 

Let’s combine our previous examples: Find the high-rated books (filter), and then just get an array of their titles (map).

JavaScript:

const books = [
  { title: 'Book A', rating: 4.8 },
  { title: 'Book B', rating: 3.2 },
  { title: 'Book C', rating: 4.6 }
];

const highRatedTitles = books
  .filter(book => book.rating >= 4.5) // Step 1: Filter
  .map(book => book.title);          // Step 2: Map

console.log(highRatedTitles);
// Output: ["Book A", "Book C"]

Conclusion

 

The map, filter, and reduce methods move you away from error-prone, index-based for loops and into the world of functional programming.

They make your code more:

  • Readable: The function’s purpose is clear from the method name (map transforms, filter selects).

  • Maintainable: You are not manually managing loop counters or creating empty arrays, which reduces potential bugs.

Start integrating these three methods into your daily coding, and you’ll find yourself writing faster, cleaner, and more expressive JavaScript!

Useful links below:

Let me & my team build you a money making website/blog for your business https://bit.ly/tnrwebsite_service

Get Bluehost hosting for as little as $1.99/month (save 75%)…https://bit.ly/3C1fZd2

Best email marketing automation solution on the market! http://www.aweber.com/?373860

Build high converting sales funnels with a few simple clicks of your mouse! https://bit.ly/484YV29

Join my Patreon for one-on-one coaching and help with your coding…https://www.patreon.com/c/TyronneRatcliff

Buy me a coffee ☕️https://buymeacoffee.com/tyronneratcliff

{ 0 comments }