This is a solution to the Todo app challenge on Frontend Mentor. Frontend Mentor challenges help you improve your coding skills by building realistic projects.
Users should be able to:
- View the optimal layout for the app depending on their device's screen size
- See hover states for all interactive elements on the page
- Add new todos to the list
- Mark todos as complete
- Delete todos from the list
- Filter by all/active/complete todos
- Clear all completed todos
- Toggle light and dark mode
- Drag and drop to reorder items on the list
- Solution URL: https://www.frontendmentor.io/solutions/responsive-todo-app-with-dark-mode-and-indexeddb-persistence-cSOVYDloZp
- Live Site URL: https://todoapp-fm.netlify.app/
- Semantic HTML5 markup
- CSS custom properties
- Flexbox
- Mobile-first workflow
- Vanilla JavaScript
- Dexie.js - For IndexedDB
This project provided excellent opportunities to deepen my understanding of several core web development concepts:
- Advanced Theme Management: Successfully implemented light and dark mode using the data-theme attribute on the element combined with CSS custom properties. This approach offers a clean and efficient way to manage themes directly through CSS variables.
<html lang="en" data-theme="dark">:root {
--body-bg: hsl(0, 0%, 98%); /* Light theme default */
}
html[data-theme="dark"] {
--body-bg: hsl(235, 21%, 11%); /* Dark theme override */
} const toggleTheme = () => {
currentTheme = currentTheme === 'light' ? 'dark' : 'light';
html.setAttribute('data-theme', currentTheme);
saveTheme();
};- Robust Data Persistence with IndexedDB via Dexie.js: Moved from localStorage to IndexedDB using the Dexie.js wrapper. This significantly improved the robustness and scalability of local data storage, handling complex data structures (like an ordered list of todos) more efficiently and asynchronously.
const db = new Dexie('TodoAppDB');
db.version(1).stores({
todos: '++id, text, completed, order',
settings: '&key, value'
});
// Example of adding a todo
const addTodo = async (text) => {
if (!text.trim()) return;
const newTodo = {
text: text.trim(),
completed: false,
order: todos.length > 0 ? todos[todos.length - 1].order + 1 : 0
};
await db.todos.add(newTodo);
newTodoInput.value = '';
await loadTodos();
};-
Drag and Drop API: Gained practical experience with the native HTML Drag and Drop API, implementing reordering functionality for the todo list. This involved understanding dragstart, dragover, and dragend events, and managing the state of the list in memory (todos array) and persisting the new order to IndexedDB.
-
Performance Optimization and Clean Code: Focused on optimizing JavaScript for better performance, particularly in DOM manipulation and event handling. Refactored code for improved readability, maintainability, and conciseness, including consolidating DOM element selections and using arrow functions and destructuring effectively.
I want to continue focusing on:
-
Accessibility (A11y): Further enhancing the app's accessibility for users with disabilities, ensuring robust ARIA attributes and keyboard navigation.
-
Performance Metrics: Deep diving into web performance metrics (e.g., Core Web Vitals) and optimizing load times and interactivity.
-
Progressive Web App (PWA): Fully exploring and implementing more PWA capabilities beyond just theme-color and manifest, such as offline support with service workers.
-
MDN Web Docs: Always an invaluable resource for understanding HTML, CSS, and JavaScript APIs, especially for the Drag and Drop API.
-
Dexie.js Documentation: The official documentation was extremely helpful for integrating IndexedDB with a clean API.
-
Frontend Mentor Community: Seeing other solutions and discussions provided great insights and alternative approaches.
- Website - https://lakhindar.is-a.dev
- Frontend Mentor - @LakhindarPal
A huge thanks to the Frontend Mentor community for providing challenging and realistic projects that help hone front-end skills.