DEV Community

Sh Raj
Sh Raj

Posted on • Updated on

Building an Offline-Enabled To-Do List Web App πŸš€

Building an Offline-Enabled To-Do List Web App

After getting huge success on my previous article. Here is a use case of building an Offline-Enabled Website.

In today's world, where connectivity isn't always guaranteed, creating web applications that work offline can greatly enhance user experience. In this tutorial, we'll walk through the process of building a simple To-Do List web app that functions both online and offline. We'll be using basic HTML, CSS, and JavaScript, along with a service worker for caching resources.

[!TIP]
See Source Code and Live Preview

Prerequisites

  • Basic knowledge of HTML, CSS, and JavaScript
  • A text editor
  • A browser that supports service workers (most modern browsers)

Setting Up the Project

Let's start by setting up the basic structure of our project. Create the following files in a new directory:

  • index.html
  • styles.css
  • app.js
  • service-worker.js

The HTML Structure (index.html)

Our main HTML file will contain the structure of our To-Do List web app. Here's a basic layout:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Offline To-Do List</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="container">
        <h1>Offline To-Do List</h1>
        <div class="form">
            <input type="text" id="taskInput" placeholder="Add new task...">
            <button onclick="addTask()">Add Task</button>
        </div>
        <ul id="taskList">
            <!-- Tasks will be dynamically added here -->
        </ul>
    </div>
    <script src="app.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Styling (styles.css)

Let's add some basic styles to make our app look presentable:

body {
    font-family: Arial, sans-serif;
    margin: 20px;
}

.container {
    max-width: 600px;
    margin: 0 auto;
}

h1 {
    text-align: center;
}

.form {
    display: flex;
    margin-bottom: 20px;
}

input[type="text"] {
    flex: 1;
    padding: 10px;
}

button {
    padding: 10px 20px;
    background-color: #007bff;
    color: #fff;
    border: none;
    cursor: pointer;
}

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

ul {
    list-style-type: none;
    padding: 0;
}

li {
    margin-bottom: 10px;
}

.completed {
    text-decoration: line-through;
    color: #888;
}
Enter fullscreen mode Exit fullscreen mode

Adding Functionality (app.js)

Our JavaScript file will handle the logic for adding tasks, toggling completion, deleting tasks, rendering tasks, and saving tasks to localStorage. It will also register the service worker.

let tasks = [];

// Check if there are tasks in localStorage
const storedTasks = localStorage.getItem('tasks');
if (storedTasks) {
    tasks = JSON.parse(storedTasks);
    renderTasks();
}

function addTask() {
    const taskInput = document.getElementById('taskInput');
    const taskText = taskInput.value.trim();
    if (taskText !== '') {
        tasks.push({ text: taskText, completed: false });
        taskInput.value = '';
        renderTasks();
        saveTasks();
    }
}

function toggleTask(index) {
    tasks[index].completed = !tasks[index].completed;
    renderTasks();
    saveTasks();
}

function deleteTask(index) {
    tasks.splice(index, 1);
    renderTasks();
    saveTasks();
}

function renderTasks() {
    const taskList = document.getElementById('taskList');
    taskList.innerHTML = '';
    tasks.forEach((task, index) => {
        const li = document.createElement('li');
        li.innerHTML = `
            <span class="${task.completed ? 'completed' : ''}" onclick="toggleTask(${index})">${task.text}</span>
            <button onclick="deleteTask(${index})">Delete</button>
        `;
        taskList.appendChild(li);
    });
}

function saveTasks() {
    localStorage.setItem('tasks', JSON.stringify(tasks));
}

// Service Worker Registration
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service-worker.js')
        .then(reg => {
            console.log('Service Worker registered');
        })
        .catch(error => {
            console.error('Service Worker registration failed:', error);
        });
}
Enter fullscreen mode Exit fullscreen mode

Service Worker (service-worker.js)

The service worker file is responsible for caching the necessary files and handling requests when the app is offline:

const cacheName = 'offline-v1';
const cacheFiles = [
    '/',
    '/index.html',
    '/styles.css',
    '/app.js'
];

self.addEventListener('install', e => {
    console.log('Service Worker: Installed');
    e.waitUntil(
        caches.open(cacheName)
        .then(cache => {
            console.log('Service Worker: Caching Files');
            cache.addAll(cacheFiles);
        })
        .then(() => self.skipWaiting())
    );
});

self.addEventListener('activate', e => {
    console.log('Service Worker: Activated');
    e.waitUntil(
        caches.keys().then(cacheNames => {
            return Promise.all(
                cacheNames.map(cache => {
                    if (cache !== cacheName) {
                        console.log('Service Worker: Clearing Old Cache');
                        return caches.delete(cache);
                    }
                })
            );
        })
    );
});

self.addEventListener('fetch', e => {
    console.log('Service Worker: Fetching');
    e.respondWith(
        fetch(e.request)
        .then(response => {
            const clone = response.clone();
            caches.open(cacheName)
                .then(cache => {
                    cache.put(e.request, clone);
                });
            return response;
        })
        .catch(() => caches.match(e.request).then(response => response))
    );
});
Enter fullscreen mode Exit fullscreen mode

Conclusion

By following this tutorial, you've learned how to create an offline-enabled To-Do List web app using basic web technologies. Users can add tasks, mark them as completed, and delete them - all while offline. The service worker ensures that the app functions seamlessly even without an internet connection by caching the necessary files.

Feel free to expand upon this project by adding more features like editing tasks, due dates, or even syncing with a backend server when connectivity is restored. This is just the beginning of what you can achieve with offline web applications!

Download This Article :- https://gist.github.com/SH20RAJ/574a952fe360ca170e81f7447626cc2a

Happy coding! πŸš€

Top comments (9)

Collapse
 
i-santosh profile image
Santosh Kumar

By the way, your example todo app is vulnerable via xss.

Still nice information

Collapse
 
fyodorio profile image
Fyodor

No way, while it’s offline… πŸ₯‚πŸ˜‚

Collapse
 
i-santosh profile image
Santosh Kumar

😝

Collapse
 
sh20raj profile image
Sh Raj

No means of vulnerability it's just a simple to-do app for demonstration purpose and it doesn't use any db or things thats requires security....
It's not a problem....
Still Thanks

Collapse
 
hiteshcodes profile image
hiteshcodes

nice app, take a look at mine πŸ˜ƒ
hitesh-todolist.netlify.app/

Collapse
 
sh20raj profile image
Sh Raj

Nice UI bro πŸš€
But offline functionality isn't added, you should add it....

Collapse
 
livetvchannels profile image
Trieu.iv

I like to use workbox
This is my app πŸ˜ƒ

Some comments may only be visible to logged-in visitors. Sign in to view all comments.