TutorialsPreview
Build a Todo App

Build a Todo AppLesson 2

LearnReferencebeginner12 minBuild a Todo App

Structure & style the app

Lesson 1 of 4 — the markup and CSS the rest of the course brings to life.

You will learn

Semantic structure for a small app and how a stylesheet turns bare markup into something you would actually use.

Prerequisites

None. If you can open a file, you can do this lesson.

01

Step 112 min

Lay down the markup and the look

GoalA static todo layout exists and looks finished — before a line of behaviour.

Good apps are built shape-first. We write the index.html structure (a form, a <ul>, a footer with filter buttons) and a styles.css that makes it calm and dark. Two rows are hard-coded so you can see the design; lesson 2 replaces them with real, JavaScript-driven items.

project · todo-app · Structure & style Open in Code
index.htmlHTML
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Todo</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<main class="app">
<h1>Today</h1>
<form id="new-todo">
<input id="title" name="title" placeholder="What needs doing?" autocomplete="off" />
<button type="submit">Add</button>
</form>
<ul id="list" class="list">
<li><span class="check"></span><span class="title">Read the brief</span><button class="remove" aria-label="Delete">×</button></li>
<li class="done"><span class="check"></span><span class="title">Open the editor</span><button class="remove" aria-label="Delete">×</button></li>
</ul>
<footer class="bar">
<span id="count">1 left</span>
<span class="filters">
<button data-filter="all" class="active">All</button>
<button data-filter="active">Active</button>
<button data-filter="done">Done</button>
</span>
</footer>
</main>
<script src="app.js"></script>
</body>
</html>
styles.cssCSS
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: start center;
padding: 6vh 16px;
font-family: system-ui, -apple-system, sans-serif;
background: #0b0e14;
color: #e7ecf3;
}
.app { width: 100%; max-width: 460px; }
h1 { font-size: 22px; letter-spacing: -0.01em; margin: 0 0 16px; }
#new-todo { display: flex; gap: 8px; margin-bottom: 18px; }
#title {
flex: 1;
padding: 11px 14px;
border-radius: 10px;
border: 1px solid #232a36;
background: #11151c;
color: inherit;
font-size: 15px;
}
#title:focus { outline: none; border-color: #6ea8fe; }
#new-todo button {
padding: 0 18px;
border-radius: 10px;
border: 1px solid #2b3340;
background: #6ea8fe;
color: #0b0e14;
font-weight: 600;
cursor: pointer;
}
.list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.list li {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 14px;
border-radius: 10px;
background: #11151c;
border: 1px solid #1c2330;
}
.check {
width: 18px;
height: 18px;
flex: none;
border-radius: 999px;
border: 1.5px solid #3a4456;
cursor: pointer;
}
.list li.done .check { background: #4ade80; border-color: #4ade80; }
.list li.done .title { color: #5b6675; text-decoration: line-through; }
.title { flex: 1; }
.remove {
border: none;
background: none;
color: #5b6675;
font-size: 20px;
line-height: 1;
cursor: pointer;
}
.remove:hover { color: #f87171; }
.bar {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 16px;
font-size: 13px;
color: #8b93a3;
}
.filters { display: flex; gap: 4px; }
.filters button {
border: 1px solid transparent;
background: none;
color: inherit;
padding: 4px 10px;
border-radius: 8px;
cursor: pointer;
}
.filters button.active { border-color: #2b3340; color: #e7ecf3; }
app.jsJAVASCRIPT
// Step 2 brings this page to life.
// For now the rows in index.html are hard-coded so you can see the design.
preview
The static app at step 1 — press Open in Code to edit it whole.

Before lesson 2

Try it

In Code, change the <h1> from "Today" to your own list name and re-run the preview.

Concepts covered · 1

More like this

P
Reference·beginner·16 min

Persist & filter

Save the list to localStorage so it is still there tomorrow, and wire the All / Active / Done filters. This is the lesson that turns a toy into something you would actually use.

W
Reference·intermediate·16 min

Write the spec the model can hit

A prompt is a specification. The difference between a junior and a senior prompt is the constraints a senior names that a junior leaves to chance. This lesson turns your architecture sketch into a prompt that produces reviewable code.

A
Reference·beginner·15 min

Add todos with JavaScript

Wire the form so typing and pressing Add creates a real item. You will hold the todos in an array and render the list from it — the pattern every UI framework formalises later.

Liked this one?

Pass it on

Discussion

Be the first to ask

Your questions stay private with the team. We can pin answers to share with everyone.

Sign in to ask a question privately on this tutorial.

Sign in

No pinned answers yet for this tutorial.