この7日間 TODOアプリ学習のゴール
この 7 日間では、「ブラウザ上で動くシンプルな TODO アプリ」を完成させます。
機能は次の 4 つに絞ります。
- テキスト入力欄にやることを書く
- 追加ボタンでリストに追加
- 削除ボタンで消す
- チェックボックスで「完了済み」を切り替え、見た目を変える
HTML/CSS は最低限にして、「JavaScriptで画面を動かす」「状態を管理する」ことに集中します。
1 日目:環境準備と「画面の骨組み」を作る
ファイルとフォルダの準備
まずは作業用フォルダを作ります。
- デスクトップなどに
todo-appフォルダを作成 - その中に
index.htmlを作る index.htmlをブラウザで開けるようにしておく(ダブルクリックでOK)
TODOアプリの最低限のHTMLを書く
index.html に、まずは画面の骨組みを書きます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>TODO アプリ</title>
<style>
body {
font-family: sans-serif;
padding: 20px;
}
.container {
max-width: 400px;
margin: 0 auto;
}
.input-area {
margin-bottom: 16px;
}
.input-area input {
width: 70%;
padding: 4px;
font-size: 16px;
}
.input-area button {
padding: 6px 10px;
font-size: 14px;
margin-left: 4px;
}
.todo-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 4px 0;
border-bottom: 1px solid #ddd;
}
.todo-text {
flex-grow: 1;
margin-left: 8px;
}
.completed {
text-decoration: line-through;
color: #888;
}
.todo-actions button {
margin-left: 4px;
font-size: 12px;
}
</style>
</head>
<body>
<div class="container">
<h1>TODO アプリ</h1>
<div class="input-area">
<input id="todo-input" type="text" placeholder="やることを入力..." />
<button id="add-button">追加</button>
</div>
<div id="todo-list">
<!-- TODO 項目がここに追加される -->
</div>
</div>
<script>
console.log("TODO アプリスタート");
</script>
</body>
</html>
ブラウザで開いて、
- タイトル「TODO アプリ」
- テキスト入力欄
- 「追加」ボタン
が表示されていれば 1 日目はOKです。
まだ TODO を追加する機能はありませんが、これが「アプリの土台」です。
2 日目:DOM を触る感覚と「1つだけ TODO を追加」してみる
DOM を通して要素を取る
JavaScript から HTML の要素を触る基本は「id で取る」ことです。<script> 内を次のように書き換えます。
<script>
const input = document.getElementById("todo-input");
const addButton = document.getElementById("add-button");
const todoList = document.getElementById("todo-list");
console.log(input);
console.log(addButton);
console.log(todoList);
</script>
ブラウザのデベロッパーツール(検証 → Console)を開くと、それぞれの要素が表示されているはずです。
これは「JavaScript側から HTML をちゃんと掴めているか」の確認です。
ボタンを押したら console.log する
まずは「イベントが動いているか」を確認します。
<script>
const input = document.getElementById("todo-input");
const addButton = document.getElementById("add-button");
const todoList = document.getElementById("todo-list");
addButton.addEventListener("click", function() {
console.log("追加ボタンが押されました");
console.log("入力されている値:", input.value);
});
</script>
ブラウザで入力欄に「牛乳を買う」などと入れて「追加」を押すと、コンソールにその文字が表示されるはずです。input.value が「入力された文字」を表します。
TODO の要素を JavaScriptで作ってみる(1件だけ)
最初は「1件だけ固定で追加」でもOKです。addEventListener の中身を、次のように書いてみてください。
addButton.addEventListener("click", function() {
const text = input.value;
const todoItem = document.createElement("div");
todoItem.className = "todo-item";
todoItem.textContent = text;
todoList.appendChild(todoItem);
});
JavaScriptポイントは次の通りです。
document.createElement("div")で新しい<div>を作るclassNameでクラスを付けて、CSS のスタイルを適用するappendChildでtodo-listの中に追加する
この時点ではチェックボックスや削除ボタンはありません。まずは「入力したテキストが下に追加される」という感覚を掴みます。
3 日目:「1アイテムの構造」を設計し、チェックボックスと削除ボタンを付ける
TODO アイテムの構造を決める
1 つの TODO アイテムは、次のような構造にします。
- チェックボックス
- テキスト部分
- 「削除」ボタン
HTML で書くとイメージはこうです(直接は書きませんが構造イメージ用)。
<div class="todo-item">
<input type="checkbox" />
<span class="todo-text">牛乳を買う</span>
<div class="todo-actions">
<button>削除</button>
</div>
</div>
これを JavaScript で組み立てます。
1アイテムを作る関数を定義する(重要)
<script> の中に、アイテムを作る関数を書きます。
function createTodoItem(text) {
const item = document.createElement("div");
item.className = "todo-item";
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
const span = document.createElement("span");
span.className = "todo-text";
span.textContent = text;
const actions = document.createElement("div");
actions.className = "todo-actions";
const deleteButton = document.createElement("button");
deleteButton.textContent = "削除";
actions.appendChild(deleteButton);
item.appendChild(checkbox);
item.appendChild(span);
item.appendChild(actions);
return item;
}
JavaScriptこの関数は、「文字列を渡すと TODO アイテムの DOM を組み立てて返す」部品です。
こうやって「作る処理」を関数にまとめておくと、追加機能を入れるときに見通しが良くなります。
追加ボタンからこの関数を使う
addButton のクリック処理を次のように変えます。
addButton.addEventListener("click", function() {
const text = input.value.trim();
if (text === "") {
return;
}
const todoItem = createTodoItem(text);
todoList.appendChild(todoItem);
input.value = "";
});
JavaScripttrim() は前後の空白を消すメソッドです。空文字のときは追加しないようにしています。
この時点で、「入力 → 追加 → TODO アイテムが表示される」ところまで行ければOKです。
4 日目:削除機能と「イベントリスナーの付け方」を深掘りする
削除ボタンにイベントを付ける
3 日目の createTodoItem 関数の中で、削除ボタンにイベントを付けます。
deleteButton.addEventListener("click", function() {
todoList.removeChild(item);
});
JavaScript最終的な createTodoItem はこうなります。
function createTodoItem(text) {
const item = document.createElement("div");
item.className = "todo-item";
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
const span = document.createElement("span");
span.className = "todo-text";
span.textContent = text;
const actions = document.createElement("div");
actions.className = "todo-actions";
const deleteButton = document.createElement("button");
deleteButton.textContent = "削除";
deleteButton.addEventListener("click", function() {
todoList.removeChild(item);
});
actions.appendChild(deleteButton);
item.appendChild(checkbox);
item.appendChild(span);
item.appendChild(actions);
return item;
}
JavaScriptここで重要なのは、「イベントの中から外側の item を参照している」ことです。
このスコープ(範囲)の感覚は、今後必ず役立ちます。
深掘り:なぜ todoList.removeChild(item) なのか
DOM の構造は「親子関係」でできています。todoList は TODO アイテムの「親」、item はその「子」です。
削除したいときは、「親から子を取り除く」という形で書きます。
だから
親要素.removeChild(子要素);
JavaScriptという書き方になるわけです。
5 日目:完了チェック(チェックボックスで見た目を変える)
完了済みTODOの見た目を決める
すでに CSS に .completed を書いてあります。
.completed {
text-decoration: line-through;
color: #888;
}
このクラスを付けたり外したりすることで、「完了済み」を表現します。
付いていれば「取り消し線+グレー」、付いていなければ普通のテキスト、というイメージです。
チェックボックスにイベントを付ける(重要)
createTodoItem 関数の中で、チェックボックスのイベントを追加します。
checkbox.addEventListener("change", function() {
if (checkbox.checked) {
span.classList.add("completed");
} else {
span.classList.remove("completed");
}
});
JavaScriptポイントは次の通りです。
changeイベントは「チェック状態が変わったとき」に発火するcheckbox.checkedがtrueならチェック済み、falseなら未チェックclassList.add/classList.removeでクラスの付け外しを行う
これで、「チェックを入れると取り消し線が付き、外すと戻る」動きが作れます。
動きを確認する
- 何個か TODO を追加する
- 任意の TODO にチェックを入れたり外したりする
- 削除ボタンで消せるか試す
ここまで出来たら、TODO アプリとして最低限使える状態になっています。
6 日目:「見直し」と「キーボード操作」などの小さな改善
Enterキーで追加できるようにする
ユーザー体験として、「入力して Enter で追加」は欲しいところです。input に対してキーイベントを付けます。
input.addEventListener("keydown", function(event) {
if (event.key === "Enter") {
addButton.click();
}
});
JavaScriptポイントは、
keydownでキーが押された瞬間をとらえるevent.key === "Enter"で Enter キーかどうか判定addButton.click()で「追加ボタンが押されたことにする」
これで、「マウスを使わずキーボードだけでも追加できる」ようになります。
追加時のバリデーションを少しだけ強くする
すでに空文字は無視していますが、スペースだけの入力も避けたいので、trim() は重要です。
さらに、TODO が多すぎるのを防ぎたいなら、上限を設けてもよいです。
例として、最大 50 件までにするとします。
addButton.addEventListener("click", function() {
const text = input.value.trim();
if (text === "") {
return;
}
if (todoList.children.length >= 50) {
alert("TODO は 50 件までです");
return;
}
const todoItem = createTodoItem(text);
todoList.appendChild(todoItem);
input.value = "";
});
JavaScriptここでの学びは、「DOM の子要素の数を数える」というテクニックと、
「仕様(上限)を自分で決めて、それをコードに落とす」感覚です。
コードを少し整理する
例えば、「TODO を追加する処理」を関数にまとめると、コードの見通しが良くなります。
function addTodo() {
const text = input.value.trim();
if (text === "") {
return;
}
const todoItem = createTodoItem(text);
todoList.appendChild(todoItem);
input.value = "";
}
addButton.addEventListener("click", addTodo);
input.addEventListener("keydown", function(event) {
if (event.key === "Enter") {
addTodo();
}
});
JavaScript同じ処理を二度書かずに、関数にして使い回す。
これはプロの現場でも非常に重要な習慣です。
7 日目:完成形のコードを通して読み、「自分の味付け」を加える
完成版の全体コード(シンプル版)
ここまでの内容を組み合わせた、1 つの完成例です。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>TODO アプリ</title>
<style>
body {
font-family: sans-serif;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 400px;
margin: 0 auto;
background-color: #fff;
border-radius: 8px;
padding: 16px;
box-shadow: 0 0 8px rgba(0,0,0,0.1);
}
h1 {
text-align: center;
margin-top: 0;
}
.input-area {
margin-bottom: 16px;
display: flex;
}
.input-area input {
flex-grow: 1;
padding: 6px;
font-size: 16px;
}
.input-area button {
padding: 6px 10px;
font-size: 14px;
margin-left: 4px;
}
#todo-list {
margin-top: 8px;
}
.todo-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 4px 0;
border-bottom: 1px solid #eee;
}
.todo-text {
flex-grow: 1;
margin-left: 8px;
word-break: break-all;
}
.completed {
text-decoration: line-through;
color: #888;
}
.todo-actions button {
margin-left: 4px;
font-size: 12px;
}
</style>
</head>
<body>
<div class="container">
<h1>TODO アプリ</h1>
<div class="input-area">
<input id="todo-input" type="text" placeholder="やることを入力..." />
<button id="add-button">追加</button>
</div>
<div id="todo-list"></div>
</div>
<script>
const input = document.getElementById("todo-input");
const addButton = document.getElementById("add-button");
const todoList = document.getElementById("todo-list");
function createTodoItem(text) {
const item = document.createElement("div");
item.className = "todo-item";
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
const span = document.createElement("span");
span.className = "todo-text";
span.textContent = text;
const actions = document.createElement("div");
actions.className = "todo-actions";
const deleteButton = document.createElement("button");
deleteButton.textContent = "削除";
checkbox.addEventListener("change", function() {
if (checkbox.checked) {
span.classList.add("completed");
} else {
span.classList.remove("completed");
}
});
deleteButton.addEventListener("click", function() {
todoList.removeChild(item);
});
actions.appendChild(deleteButton);
item.appendChild(checkbox);
item.appendChild(span);
item.appendChild(actions);
return item;
}
function addTodo() {
const text = input.value.trim();
if (text === "") {
return;
}
const todoItem = createTodoItem(text);
todoList.appendChild(todoItem);
input.value = "";
input.focus();
}
addButton.addEventListener("click", addTodo);
input.addEventListener("keydown", function(event) {
if (event.key === "Enter") {
addTodo();
}
});
</script>
</body>
</html>
HTML細かい書き方は変えても構いません。
重要なのは、「入力 → 追加 → 完了チェック → 削除」の流れを、
DOM 操作とイベント、そして状態の変化として理解できていることです。
自分のアレンジを入れてみるアイデア
ここから先は「遊び」です。例えば次のような改良が考えられます。
- 「完了済みだけを非表示にする」チェックボックスを追加
- 「すべて削除」ボタンを追加
- TODO をブラウザのローカルストレージに保存して、ページをリロードしても残るようにする
- 優先度(高・中・低)をドロップダウンで選べるようにする
どれも難しそうに見えますが、実は今学んだ DOM とイベント、変数の管理を応用しているだけです。
このTODOアプリで身につく「本物の基礎」
この 7 日間で、ただ TODO アプリを作っただけではありません。
あなたは次の感覚をちゃんと身につけています。
- HTML の「部品」と JavaScript の「ロジック」を、DOM を通じてつなぐ感覚
- ボタンや入力欄、チェックボックスなどに「イベントで動きを付ける」方法
- 1 つのTODOアイテムを「構造設計 → 関数化 → 再利用」という流れで組み立てる考え方
- 少しずつ仕様を足しながら、アプリを育てていくプロセス

