Close Menu
    Facebook X (Twitter) Instagram
    LudiflexLudiflex
    • Home
    • Blog
    • HTML & CSS
      • Card Design
      • Login Forms
      • Navigation Bar
      • Website Designs
    • JavaScript
      • JavaScript Projects
    • Bootstrap
    • PHP
    LudiflexLudiflex
    Home » Blog » How to Create a To-Do List App Using HTML, CSS, and JavaScript
    JavaScript

    How to Create a To-Do List App Using HTML, CSS, and JavaScript

    LudiflexBy LudiflexDecember 16, 2024Updated:December 16, 2024No Comments8 Mins Read

    Building a to-do list application is an excellent project for diving into the world of web development. It’s simple, practical, and teaches you how HTML, CSS, and JavaScript work together to build interactive applications. At the end of this tutorial, you’ll have a modern, functional to-do list app that you will be able to use and modify as you like.

    1. Setting Up Your Project

    First things first, organize your project. You’ll need three files:

    • index.html: The skeleton of your app.
    • style.css: The design and layout.
    • script.js: The brain of the app that makes everything work.

    Place these files in a folder, and you’re ready to roll!


    2. Structuring with HTML

    In your index.html file, start by laying out the structure of your app. Here’s what we’re building:

    • A title to give your app a name.
    • An input section where users can type in their tasks.
    • A sort button to organize tasks.
    • Two sections: one for uncompleted tasks and another for completed tasks.
    The HTML is straightforward. We’re using semantic elements like <div>, <input>, and <ul> to keep things organized. We’ve also linked our CSS for styling and JavaScript for functionality.

    Here’s how it works:

    • The Input Section: This is where users type new tasks and click the “Add” button to add them to the list.
    • Task Sections: Tasks are displayed in two categories: uncompleted and completed. You can toggle these sections open or closed for better organization.
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Modern Todo List</title>
        <link rel="stylesheet" href="style.css">
        <link href='https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css' rel='stylesheet'>
    </head>
    <body>
        <div class="container">
            <div class="todo-title">
                <h1>Todo List</h1>
            </div>
            
            <div class="input-section">
                <input type="text" id="todoInput" placeholder="Add a new task...">
                <button class="add-btn" onclick="addTodo()"><i class='bx bx-list-plus' ></i> Add</button>
            </div>
    
            <div class="sort-section">
                <button class="sort-button" onclick="toggleSort()">Sort by Oldest <i class='bx bx-sort' ></i></button>
            </div>
    
            <div class="todo-section">
                <div class="section-header active" onclick="toggleSection('uncompleted')">
                    <div class="section-header-row">
                        <h2>Uncompleted Tasks</h2>
                        <span class="count" id="uncompleted-count">0</span>
                    </div>
                    <span class="chevron"><i class='bx bx-chevron-down' ></i></span>
                </div>
                <div class="section-content expanded" id="uncompleted-section">
                    <ul id="uncompletedList">
                        <li class="todo-item">
                            <input type="checkbox" class="checkbox">
                            <span class="todo-text">Play games</span>
                            <button class="delete-btn"><i class='bx bx-trash' ></i></button>
                        </li>
                    </ul>
                </div>
            </div>
    
            <div class="todo-section">
                <div class="section-header" onclick="toggleSection('completed')">
                    <div class="section-header-row">
                        <h2>Completed Tasks</h2>
                        <span class="count" id="completed-count">0</span>
                    </div>
                    <span class="chevron"><i class='bx bx-chevron-down' ></i></span>
                </div>
                <div class="section-content" id="completed-section">
                    <ul id="completedList"></ul>
                </div>
            </div>
        </div>
    
        <script src="script.js"></script>
    </body>
    </html>

    3. Adding Styles with CSS

    Now for the fun part—making your app look good! CSS is where you define how your app appears, from colors and fonts to animations.

    • The background of the app is a soothing blue (#051B24), with the task container in a clean white box to stand out.
    • Tasks are displayed in neatly styled boxes with smooth animations when they are added or toggled.
    • Buttons change color when hovered over, providing interactive feedback.

    These styles create a polished and modern interface that’s user-friendly and aesthetically pleasing.

    @import url('https://fonts.googleapis.com/css2?family=Mr+Dafoe&family=Outfit:wght@100..900&display=swap');
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
        font-family: 'Outfit', sans-serif;
    }
    
    body {
        background:#051B24;
        padding: 40px 20px;
    }
        
    .container {
        margin: 0 auto;
        display: flex;
        flex-direction: column;
        gap: 20px;
        max-width: 600px;
        background: #E8F3F9;
        padding: 20px;
        border-radius: 12px;
        box-shadow: 0 6px 10px rgba(0, 0, 0, 0.4);
    }
    
    .todo-title h1 {
        color: #1a1a1a;
        text-align: center;
    }
    
    .input-section {
        display: flex;
        align-items: center;
        border: 1px solid #ccc;
        border-radius: 10px;
        background-color: #fff;
    }
    
    input[type="text"] {
        width: 100%;
        padding: 12px;
        font-size: 16px;
        border: none;
        border-radius: 10px;
        transition: border-color 0.3s;
        outline: none;
    }
    
    
    button {
        display: flex;
        align-items: center;
        gap: 10px;
        color: white;
        border: none;
        cursor: pointer;
        font-size: 16px;
        transition: background 0.3s;
    }
    
    button:hover {
        background: #45a049;
    }
    .add-btn{
        margin-right: 4px;
        background: #4CAF50;
        border-radius: 8px;
        padding: 8px 20px;
    }
    .sort-section {
       display: flex;
       justify-content: right;
    }
    
    .sort-button {
        background-color: #fff;
        color: #000;
        border: 1px solid #ccc;
        padding: 8px 16px;
        font-size: 14px;
        border-radius: 10px;
    }
    
    .sort-button:hover {
        background: #eee;
    }
    
    .todo-section {
        border: 1px solid #e0e0e0;
        background: #fff;
        border-radius: 8px;
        overflow: hidden;
    }
    
    .section-header {
        background: #f8f9fa;
        padding: 12px;
        cursor: pointer;
        display: flex;
        justify-content: space-between;
        align-items: center;
        border-bottom: 1px solid #e0e0e0;
    }
    .section-header-row{
        display: flex; 
        align-items: center; 
        gap: 10px;
    }
    
    .section-header h2 {
        font-size: 18px;
        color: #333;
    }
    
    .section-header .count {
        background: #e0e0e0;
        padding: 2px 8px;
        border-radius: 12px;
        font-size: 14px;
    }
    
    .section-content {
        max-height: 0;
        overflow: hidden;
        transition: max-height .3s ease-out;
    }
    
    .section-content.expanded {
        overflow: auto;
        max-height: 1000px;
    }
    
    .todo-item {
        display: flex;
        align-items: center;
        padding: 12px;
        background: #f8f9fa;
        margin: 8px;
        border-radius: 8px;
        animation: slideIn 0.3s ease;
    }
    
    @keyframes slideIn {
        from {
            opacity: 0;
            transform: translateY(-10px);
        }
        to {
            opacity: 1;
            transform: translateY(0);
        }
    }
    
    .todo-text {
        flex: 1;
        margin-right: 10px;
    }
    
    .todo-item.completed .todo-text {
        text-decoration: line-through;
        color: #666;
    }
    
    .delete-btn {
        background: none;
        color: #8a2727;
        padding: 12px;
        border-radius: 100%;
    }
    
    .delete-btn:hover {
        background: #eee;
    }
    
    .chevron {
        transition: transform 0.3s ease;
        font-size: 20px;
    }
    
    .section-header.active .chevron {
        transform: rotate(180deg);
    }
    .checkbox{
        appearance: none;
        background-color: transparent;
        width: 20px;
        height: 20px;
        border: 1px solid #666;
        border-radius: 100%;
        display: grid;
        place-content: center;
        margin-right: 10px;
        cursor: pointer;
    }
    .checkbox::before{
        content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 -2 24 24' style='fill: rgba(255, 255, 255, 1);transform: ;msFilter:;'%3E%3Cpath d='m10 15.586-3.293-3.293-1.414 1.414L10 18.414l9.707-9.707-1.414-1.414z'%3E%3C/path%3E%3C/svg%3E");
        transform: scale(0);
    }
    .checkbox:checked{
        background-color: #8d51e8;
        border-color: #8d51e8;
    }
    .checkbox:checked::before{
        transform: scale(1);
    }

    4. Bringing It to Life with JavaScript

    Here’s where the magic happens! JavaScript gives our app the functionality it needs.

    • Adding Tasks: When a user types a task and clicks “Add,” JavaScript captures the input, creates a new task element, and adds it to the uncompleted tasks list.
    • Marking Tasks as Complete: When a task is marked complete, it moves from the uncompleted list to the completed list. This is handled by toggling a completed status in the data.
    • Deleting Tasks: Each task comes with a delete button. Clicking it removes the task from the list and updates the display.
    • Sorting Tasks: A sort button allows users to reorder tasks by the time they were added, either newest first or oldest first.

    All of this is managed dynamically using JavaScript’s DOM manipulation methods.

    let todos = JSON.parse(localStorage.getItem('todos')) || [];
    let isLatestFirst = JSON.parse(localStorage.getItem('isLatestFirst')) || true;
    
    document.getElementById('todoInput').addEventListener('keypress', function(e) {
        if (e.key === 'Enter') {
            addTodo();
        }
    });
    
    function toggleSection(section) {
        const content = document.getElementById(`${section}-section`);
        const header = content.previousElementSibling;
        content.classList.toggle('expanded');
        header.classList.toggle('active');
    }
    
    function addTodo() {
        const input = document.getElementById('todoInput');
        const text = input.value.trim();
        
        if (text) {
            const todo = {
                id: Date.now(),
                text: text,
                completed: false,
                timestamp: new Date()
            };
            
            todos.push(todo);
            saveTodos(); // Save to local storage
            input.value = '';
            renderTodos();
        } 
    }
    
    function deleteTodo(id) {
        todos = todos.filter(todo => todo.id !== id);
        saveTodos(); // Save to local storage
        renderTodos();
    }
    
    function toggleComplete(id) {
        todos = todos.map(todo => 
            todo.id === id ? {...todo, completed: !todo.completed} : todo
        );
        saveTodos(); // Save to local storage
        renderTodos();
    }
    
    function toggleSort() {
        isLatestFirst = !isLatestFirst;
        localStorage.setItem('isLatestFirst', JSON.stringify(isLatestFirst)); // Save sort preference
        const button = document.querySelector('.sort-button');
        button.innerHTML = isLatestFirst ? "Sort by Oldest <i class='bx bx-sort' ></i>" : "Sort by Latest <i class='bx bx-sort' ></i>";
        renderTodos();
    }
    
    function renderTodos() {
        const uncompletedList = document.getElementById('uncompletedList');
        const completedList = document.getElementById('completedList');
        uncompletedList.innerHTML = '';
        completedList.innerHTML = '';
        
        const sortedTodos = [...todos].sort((a, b) => {
            const dateA = new Date(a.timestamp);
            const dateB = new Date(b.timestamp);
    
            return isLatestFirst ? 
                dateB - dateA : 
                dateA - dateB;
        });
    
        let completedCount = 0;
        let uncompletedCount = 0;
    
        sortedTodos.forEach(todo => {
            const li = document.createElement('li');
            li.className = `todo-item ${todo.completed ? 'completed' : ''}`;
            
            li.innerHTML = `
                <input type="checkbox" 
                       class="checkbox" 
                       ${todo.completed ? 'checked' : ''} 
                       onclick="toggleComplete(${todo.id})">
                <span class="todo-text">${todo.text}</span>
                <button class="delete-btn" onclick="deleteTodo(${todo.id})"><i class='bx bx-trash' ></i></button>
            `;
            
            if (todo.completed) {
                completedList.appendChild(li);
                completedCount++;
            } else {
                uncompletedList.appendChild(li);
                uncompletedCount++;
            }
        });
    
        // Update counters
        document.getElementById('completed-count').textContent = completedCount;
        document.getElementById('uncompleted-count').textContent = uncompletedCount;
    
        // Update the sort button label on render
        const button = document.querySelector('.sort-button');
        button.innerHTML = isLatestFirst ? "Sort by Oldest <i class='bx bx-sort' ></i>" : "Sort by Latest <i class='bx bx-sort' ></i>";
    }
    
    // Save todos to local storage
    function saveTodos() {
        localStorage.setItem('todos', JSON.stringify(todos));
        localStorage.setItem('isLatestFirst', JSON.stringify(isLatestFirst));
    }
    
    // Initial load from local storage and render
    // renderTodos();
    window.onload = function() {
        renderTodos();
        // restoreSectionStates();
    };

    5. Enhancing User Experience

    We’ve added some extra features to make this app even better:

    • Local Storage: The app saves your tasks in the browser’s local storage, so they’re still there when you refresh the page.
    • Expand/Collapse Sections: You can collapse the completed or uncompleted sections to focus on what matters most.
    • Interactive Animations: Tasks slide into view when added, creating a smooth and satisfying user experience.
    • Responsive Design: The app adjusts seamlessly to different screen sizes, so it looks great on desktops, tablets, and phones.

    Conclusion

    And that’s it! You’ve built a fully functional to-do list app using HTML, CSS, and JavaScript. Isn’t it amazing how just a few lines of code can create something so practical and beautiful?

    This project is a great starting point, but don’t stop here. You can keep improving your app by adding features like:

    • Dark Mode for a night-friendly interface.
    • Priority Levels for tasks.
    • Search Functionality to quickly find tasks.

    Now it’s your turn to experiment and make it your own. Happy coding!

    HTML and CSS Javascript to do list
    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
    Previous ArticleLogin and Register App using React and OneEntry Headless CMS
    Next Article Top 20 Essential Shortcuts for Visual Studio Code You Should Know
    Ludiflex
    • Website

    Related Posts

    HTML & CSS

    Build a Seamless PHP & AJAX Login and Registration System with No Page Reloads!

    February 1, 2025
    HTML & CSS

    How to Build a Modern, Responsive Login & Registration Form with HTML, CSS, and JavaScript (Step-by-Step Guide)

    February 1, 2025
    JavaScript

    Login and Register App using React and OneEntry Headless CMS

    July 4, 2024
    Add A Comment
    Leave A Reply Cancel Reply

    Follow Us
    • YouTube
    • Instagram
    • TikTok
    • Twitter
    Recent Posts

    Build a Seamless PHP & AJAX Login and Registration System with No Page Reloads!

    How to Build a Modern, Responsive Login & Registration Form with HTML, CSS, and JavaScript (Step-by-Step Guide)

    Top 20 Essential Shortcuts for Visual Studio Code You Should Know

    How to Create a To-Do List App Using HTML, CSS, and JavaScript

    Login and Register App using React and OneEntry Headless CMS

    Facebook X (Twitter) Instagram Pinterest
    © 2025 Ludiflex. Made with ♥ by Ludiflex.

    Type above and press Enter to search. Press Esc to cancel.