Coding, Insights, and Digital Discoveries 👩🏻💻
From Stay-at-Home Mom to a Developer After 50
Hey there! I want to share my recent journey of building a Todo app using vanilla JavaScript. After spending a year working with React and Next.js, I felt the need to go back to basics and brush up on my core JavaScript skills. You know how it is - when you work with frameworks for too long, sometimes you need to reconnect with the fundamentals!
I first published a simple version of the To-Do List on GitHub Pages:
👉 Live Demo: My First To-Do List App
This initial version included only basic features:
✅ A task input box with an "Add Task" button.
✅ Newly added tasks appear instantly in the app.
✅ Each task can be deleted.
✅ Tasks are stored in local storage
, so they persist after the app is closed and reopened.
At this stage, the app was fully functional but very simple. I wanted to enhance it by adding more interactive features.
As I worked on improving the app, I explored different ways to dynamically generate task elements in JavaScript. This led me to write an article comparing innerHTML
vs. createElement()
for rendering elements—focusing on security, performance, and maintainability.
I then introduced several key enhancements:
While working on the completed tasks feature, I had to choose between using for...of
and map()
for looping through tasks. I ended up going with for...of
and wrote about my reasoning in a separate article.
Building the task lists toggle feature led me to learn more about memory management and web performance optimization - you can read about it here.
These updates made the app more user-friendly and dynamic. But I wanted to take it a step further—making it installable as a PWA.
A Progressive Web App (PWA) lets a website work just like a native app - you can install it on your device and use it even without internet. Since I often use sticky notes on my laptop for todos, I thought: why not make my todo app installable on both desktop and mobile? After deploying the final version and installing it on my laptop and phone, I found it super convenient for managing tasks. The app feels smooth and intuitive whether I'm adding new todos, checking off completed items, or editing existing tasks. Let me show you how I added the PWA functionality.
👉 Check out my deployed To-Do App.
manifest.json
file, it tells the browser how the app should behave when installed.manifest.json
:{
"name": "My To-Do List",
"short_name": "To-Do",
"description": "A simple to-do list with offline support",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#4CAF50",
"icons": [
{
"src": "icons/icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
manifest.json
in index.html
:<head>
tag, add:<link rel="manifest" href="manifest.json">
Now, the app can be installed on mobile devices and desktops!
service-worker.js
const CACHE_NAME = "todo-cache-v1";
const urlsToCache = [
"index.html",
"style.css",
"dist/output.css",
"script.js",
"manifest.json",
"icons/icon-192.png",
"icons/icon-512.png"
];
// Install Service Worker & Cache Files
self.addEventListener("install", event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
console.log("Caching static files...");
return cache.addAll(urlsToCache);
})
);
});
// Fetch Cached Files When Offline & Update Cache When Online
self.addEventListener("fetch", event => {
event.respondWith(
fetch(event.request)
.then(response => {
// Clone response & update cache
let responseClone = response.clone();
caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, responseClone);
});
return response;
})
.catch(() => caches.match(event.request)) // If offline, serve cached files
);
});
// Delete Old Cache & Activate New Service Worker
self.addEventListener("activate", event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cache => {
if (cache !== CACHE_NAME) {
return caches.delete(cache);
}
})
);
})
);
});
script.js
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("service-worker.js")
.then(reg => {
console.log("Service Worker Registered!", reg);
reg.onupdatefound = () => {
const newWorker = reg.installing;
newWorker.onstatechange = () => {
if (newWorker.state === "installed" && navigator.serviceWorker.controller) {
showUpdateNotification();
}
};
};
})
.catch(err => console.log("Service Worker Failed!", err));
}
// Show update notification
function showUpdateNotification() {
const updateBanner = document.createElement("div");
updateBanner.innerHTML = `
<div style="position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%);
background: #333; color: white; padding: 10px 20px; border-radius: 5px;">
A new update is available. <button id="refreshApp">Update</button>
</div>
`;
document.body.appendChild(updateBanner);
document.getElementById("refreshApp").addEventListener("click", () => {
location.reload();
});
}
Now, users get an update prompt when a new version is available!
I'm hosting the app on Netlify, which is great because it automatically deploys whenever I push updates to GitHub. The service worker handles updates smoothly - when there's a new version, users get a notification to refresh the app.
service-worker.js
has a CACHE-NAME
defined:
const CACHE_NAME = "todo-cache-v2"; // Increment the version number
After I push the update to GitHub, the Netlify will redeploy the new version, and users will automatically get the new version after refresh the app.
Now, the app is:
✅ Installable on desktops & smartphones
✅ Works offline with cached tasks
✅ Auto-updates when I push new code with more features in the future.
This project really helped me reconnect with vanilla JavaScript. Sometimes going back to basics is exactly what I need to become a better developer. Plus, I ended up with a practical app that I actually use daily! It's amazing how a simple todo list helped me brush up on so much about:
The best part is that anyone can install it on their device and use it offline. It's become more than just a learning exercise - it's a tool that people can actually use. Cheer!🍻