This is the first post of Building a Minimalist Task Manager series
Welcome to the first post in our Building a Minimalist Task Manager series! If you’re tired of reaching for React every time you want to build something interactive, or if you’re just starting your JavaScript journey and want to understand how web apps actually work under the hood, you’re in the right place.
Over the next few posts, we’ll build a clean, focused task manager that enforces a “three tasks only” rule to help you stay focused. But today? We’re keeping it simple and laying the groundwork with pure HTML, CSS, and vanilla JavaScript.
What We’re Building Today
Think of today’s version as the skeleton of our app. We’ll create:
- A basic input field where users can type tasks
- An “Add Task” button that actually does something
- A container where tasks will appear
- Just enough CSS to make it not look like it crawled out of 1995
No fancy animations, no localStorage persistence, and definitely no three-task limit yet. We’re building the foundation that everything else will sit on.
The HTML Structure
Let’s start with a simple HTML structure. Create an index.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Minimalist Task Manager</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<header>
<h1>Focus Tasks</h1>
<p>Stay focused, stay productive</p>
</header>
<div class="task-input-section">
<input type="text" id="taskInput" placeholder="What needs to get done?" maxlength="100">
<button id="addTaskBtn">Add Task</button>
</div>
<div class="task-list-container">
<ul id="taskList" class="task-list">
<!-- Tasks will be dynamically added here -->
</ul>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
Nothing fancy here - just a container with a header, an input section, and a placeholder for our task list. Notice I’m keeping the IDs descriptive and the structure semantic.
Adding Some Style (styles.css)
Now let’s add some basic CSS to make it look clean and readable:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background-color: #f5f7fa;
color: #2d3748;
line-height: 1.6;
}
.container {
max-width: 600px;
margin: 0 auto;
padding: 2rem;
}
header {
text-align: center;
margin-bottom: 2rem;
}
header h1 {
font-size: 2.5rem;
font-weight: 300;
color: #1a202c;
margin-bottom: 0.5rem;
}
header p {
color: #718096;
font-size: 1.1rem;
}
.task-input-section {
display: flex;
gap: 0.5rem;
margin-bottom: 2rem;
}
#taskInput {
flex: 1;
padding: 0.75rem;
border: 2px solid #e2e8f0;
border-radius: 6px;
font-size: 1rem;
transition: border-color 0.2s;
}
#taskInput:focus {
outline: none;
border-color: #4299e1;
}
#addTaskBtn {
padding: 0.75rem 1.5rem;
background-color: #4299e1;
color: white;
border: none;
border-radius: 6px;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.2s;
}
#addTaskBtn:hover {
background-color: #3182ce;
}
.task-list {
list-style: none;
}
.task-item {
background: white;
margin-bottom: 0.5rem;
padding: 1rem;
border-radius: 6px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
display: flex;
justify-content: space-between;
align-items: center;
}
.task-text {
font-size: 1rem;
color: #2d3748;
}
.delete-btn {
background-color: #e53e3e;
color: white;
border: none;
padding: 0.25rem 0.5rem;
border-radius: 4px;
cursor: pointer;
font-size: 0.875rem;
}
.delete-btn:hover {
background-color: #c53030;
}
I’m going for a clean, modern look with subtle shadows and a pleasant color palette. The CSS uses flexbox for layout and includes some nice hover effects to make the interface feel responsive.
The JavaScript Magic (script.js)
Now for the fun part - let’s bring our task manager to life:
// Get references to our DOM elements
const taskInput = document.getElementById('taskInput');
const addTaskBtn = document.getElementById('addTaskBtn');
const taskList = document.getElementById('taskList');
// Array to store our tasks (for now, just in memory)
let tasks = [];
// Function to create a new task element
function createTaskElement(taskText, taskId) {
const li = document.createElement('li');
li.className = 'task-item';
li.innerHTML = `
<span class="task-text">${taskText}</span>
<button class="delete-btn" onclick="deleteTask(${taskId})">Delete</button>
`;
return li;
}
// Function to add a new task
function addTask() {
const taskText = taskInput.value.trim();
// Check if input is empty
if (taskText === '') {
alert('Please enter a task!');
return;
}
// Create task object
const task = {
id: Date.now(), // Simple ID generation using timestamp
text: taskText
};
// Add to our tasks array
tasks.push(task);
// Create and add the task element to the DOM
const taskElement = createTaskElement(task.text, task.id);
taskList.appendChild(taskElement);
// Clear the input field
taskInput.value = '';
console.log('Current tasks:', tasks); // For debugging
}
// Function to delete a task
function deleteTask(taskId) {
// Remove from tasks array
tasks = tasks.filter(task => task.id !== taskId);
// Remove from DOM
const taskElements = taskList.children;
for (let i = 0; i < taskElements.length; i++) {
const deleteBtn = taskElements[i].querySelector('.delete-btn');
if (deleteBtn.onclick.toString().includes(taskId)) {
taskList.removeChild(taskElements[i]);
break;
}
}
console.log('Tasks after deletion:', tasks); // For debugging
}
// Event listeners
addTaskBtn.addEventListener('click', addTask);
// Allow adding tasks by pressing Enter
taskInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
addTask();
}
});
The JavaScript is straightforward but covers the essentials:
- We maintain a
tasksarray to keep track of our data - The
addTask()function validates input, creates a task object, and updates both our data and the DOM - The
deleteTask()function removes tasks from both the array and the display - We handle both button clicks and Enter key presses for better UX
What We’ve Accomplished
And there you have it! In just three files, we’ve created a functional task manager that can:
- Add new tasks with a clean interface
- Delete tasks individually
- Handle keyboard input (Enter to add)
- Store tasks in memory (temporarily)
Sure, it’s not fancy yet, and your tasks disappear when you refresh the page, but that’s the beauty of building incrementally. We have a solid foundation that we can build upon.
What’s Next?
In the next post, we’ll add the core “focus mode” feature by limiting users to just three active tasks. We’ll also implement localStorage to persist tasks between browser sessions.
The current version is like a rough sketch - functional but basic. Each post will add more features and polish until we have something truly useful.
Try out the current version, add some tasks, delete a few, and get a feel for the basic functionality. Next time, we’ll make it actually useful for staying focused and productive!
Happy coding!