Brtest Tutorial
Project: Interactive To-Do List
In this project, you will build a simple To-Do app where users can add tasks, mark them as done, and delete them. You will use arrays to store tasks, events to handle clicks, and DOM methods to update the list on the page.
Features
- Add a new task
- Mark a task as completed
- Delete a task
- Persist tasks for this session using JavaScript memory (array)
Starter UI
Example
Basic HTML and CSS for the app:
<style>
body { font-family: Arial, sans-serif; background: #f7f7f7; margin: 0; }
.app { max-width: 420px; margin: 24px auto; background: #fff; padding: 16px 16px 8px; border-radius: 10px; box-shadow: 0 6px 18px rgba(0,0,0,0.06); }
h3 { margin: 0 0 12px; }
.row { display: flex; gap: 8px; }
#taskInput { flex: 1; padding: 10px; border: 1px solid #ddd; border-radius: 6px; }
#addBtn { padding: 10px 14px; background: #111; color: #fff; border: 0; border-radius: 6px; cursor: pointer; }
#addBtn:hover { background: #333; }
ul { list-style: none; padding: 0; margin: 12px 0 0; }
li { display: grid; grid-template-columns: 24px 1fr auto; align-items: center; gap: 10px; padding: 10px; border: 1px solid #eee; border-radius: 8px; margin-bottom: 8px; background: #fafafa; }
li.done .text { text-decoration: line-through; color: #888; }
.del { background: #eee; border: 0; padding: 6px 10px; border-radius: 6px; cursor: pointer; }
.del:hover { background: #e2e2e2; }
.empty { color: #777; text-align: center; margin: 12px 0 4px; }
</style>
<div class='app'>
<h3>To-Do List</h3>
<div class='row'>
<input id='taskInput' placeholder='Add a new task' aria-label='Task'>
<button id='addBtn'>Add</button>
</div>
<p id='emptyMsg' class='empty'>No tasks yet</p>
<ul id='list'></ul>
</div>
Try it Yourself »
Core JavaScript
We will store tasks in an array of objects: { id, text, done }.
Rendering will rebuild the list whenever the array changes.
Example
App logic: add, toggle done, delete, and render:
<script>
// State
let tasks = [];
let nextId = 1;
// Elements
const input = document.getElementById('taskInput');
const addBtn = document.getElementById('addBtn');
const list = document.getElementById('list');
const emptyMsg = document.getElementById('emptyMsg');
// Render function
function render() {
list.innerHTML = '';
if (tasks.length === 0) {
emptyMsg.style.display = 'block';
return;
}
emptyMsg.style.display = 'none';
for (const task of tasks) {
const li = document.createElement('li');
if (task.done) li.classList.add('done');
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.checked = task.done;
checkbox.setAttribute('aria-label', 'Mark done');
checkbox.addEventListener('change', () => toggleDone(task.id));
const span = document.createElement('span');
span.className = 'text';
span.textContent = task.text;
const delBtn = document.createElement('button');
delBtn.className = 'del';
delBtn.textContent = 'Delete';
delBtn.addEventListener('click', () => removeTask(task.id));
li.appendChild(checkbox);
li.appendChild(span);
li.appendChild(delBtn);
list.appendChild(li);
}
}
// Actions
function addTask() {
const text = input.value.trim();
if (text === '') return;
tasks.push({ id: nextId++, text, done: false });
input.value = '';
render();
}
function toggleDone(id) {
const t = tasks.find(x => x.id === id);
if (t) { t.done = !t.done; render(); }
}
function removeTask(id) {
tasks = tasks.filter(x => x.id !== id);
render();
}
// Events
addBtn.addEventListener('click', addTask);
input.addEventListener('keydown', e => {
if (e.key === 'Enter') addTask();
});
// Initial
render();
</script>
Try it Yourself »
Optional: Save To Local Storage
Keep tasks between page reloads by saving to localStorage.
Example
Persist and load tasks:
<script>
// Load saved tasks
function load() {
try {
const raw = localStorage.getItem('todo_tasks');
const rawId = localStorage.getItem('todo_nextId');
tasks = raw ? JSON.parse(raw) : [];
nextId = rawId ? Number(rawId) : 1;
} catch {
tasks = [];
nextId = 1;
}
}
function save() {
localStorage.setItem('todo_tasks', JSON.stringify(tasks));
localStorage.setItem('todo_nextId', String(nextId));
}
// Wrap render to also save
const _render = render;
render = function() { _render(); save(); };
// Load then render
load();
render();
</script>
Try it Yourself »
Accessibility Tips
- Use clear button text like 'Add' and 'Delete'.
- Add
aria-labelto checkboxes and buttons when needed. - Ensure keyboard support: adding with Enter key, tabbing to buttons.
Challenges
- Add an 'Edit' button that lets you modify a task's text inline.
- Add a filter row: All, Active, Completed.
- Show a counter: '3 items left'.
- Prevent duplicate empty tasks and trim whitespace automatically.
Summary
- Built a To-Do List using arrays, events, and DOM updates.
- Implemented add, toggle, delete, and render functions.
- Optionally persisted tasks using
localStorage.
Next, you will learn how to work with JavaScript Strings and Numbers in more depth, including common methods and formatting.