프로젝트 소개 및 목표
🔗 관련 에러 해결 가이드
이 30분만에 만드는 Todo App 완성 가이드는 초보 개발자부터 중급 개발자까지 누구나 따라할 수 있는 실전 프로젝트입니다. 단순히 할 일을 추가하고 삭제하는 기능을 넘어, 로컬 스토리지를 활용한 데이터 영속성, 필터링 기능, 그리고 반응형 UI까지 구현합니다. 이 가이드를 통해 바닐라 자바스크립트의 DOM 조작, 이벤트 핸들링, 상태 관리의 기초를 탄탄히 다질 수 있습니다. 완성된 Todo App은 포트폴리오에 추가할 수 있는 실용적인 프로젝트가 될 것입니다. 30분이라는 짧은 시간 안에 완전히 작동하는 애플리케이션을 만들어보면서 개발의 즐거움을 느껴보세요.
필요한 기술 스택
이 프로젝트는 최소한의 기술 스택으로 구현됩니다:
- HTML5: 시맨틱 마크업을 활용한 구조 설계
- CSS3: Flexbox를 이용한 반응형 레이아웃과 모던한 스타일링
- Vanilla JavaScript (ES6+): 프레임워크 없이 순수 자바스크립트로 구현
- Local Storage API: 브라우저 로컬 스토리지를 활용한 데이터 저장
별도의 빌드 도구나 프레임워크가 필요 없으므로 브라우저만 있으면 바로 시작할 수 있습니다. 코드 에디터는 VS Code를 추천하며, Live Server 익스텐션을 설치하면 실시간으로 결과를 확인할 수 있습니다.
프로젝트 셋업
먼저 프로젝트 폴더를 생성하고 기본 파일 구조를 만들어봅시다:
mkdir todo-app
cd todo-app
touch index.html style.css app.js
이제 index.html 파일에 기본 HTML 구조를 작성합니다. head 태그에는 CSS 파일을 연결하고, body 태그 하단에는 JavaScript 파일을 연결합니다. 시맨틱 태그를 사용하여 접근성을 고려한 마크업을 작성하세요. viewport 메타 태그를 추가하여 모바일 반응형을 준비합니다. 폰트는 Google Fonts의 Poppins를 사용하여 모던한 느낌을 연출합니다. 전체적인 레이아웃은 container 안에 header, main, footer 영역으로 구성됩니다.
단계별 구현 과정
Step 1: HTML 구조 만들기 (5분)
먼저 기본적인 HTML 구조를 완성합니다:
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Todo App - 30분 완성</title>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<header>
<h1>📝 My Todo List</h1>
</header>
<main>
<div class="input-section">
<input type="text" id="todoInput" placeholder="새로운 할 일을 입력하세요...">
<button id="addBtn">추가</button>
</div>
<div class="filter-section">
<button class="filter-btn active" data-filter="all">전체</button>
<button class="filter-btn" data-filter="active">진행중</button>
<button class="filter-btn" data-filter="completed">완료</button>
</div>
<ul id="todoList" class="todo-list"></ul>
</main>
</div>
<script src="app.js"></script>
</body>
</html>
Step 2: CSS 스타일링 (8분)
모던하고 깔끔한 UI를 위한 CSS를 작성합니다:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Poppins', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.container {
background: white;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
width: 100%;
max-width: 600px;
padding: 40px;
}
header h1 {
color: #333;
text-align: center;
margin-bottom: 30px;
font-size: 2rem;
}
.input-section {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
#todoInput {
flex: 1;
padding: 15px;
border: 2px solid #e0e0e0;
border-radius: 10px;
font-size: 16px;
transition: border-color 0.3s;
}
#todoInput:focus {
outline: none;
border-color: #667eea;
}
#addBtn {
padding: 15px 30px;
background: #667eea;
color: white;
border: none;
border-radius: 10px;
font-weight: 600;
cursor: pointer;
transition: background 0.3s;
}
#addBtn:hover {
background: #5568d3;
}
.filter-section {
display: flex;
gap: 10px;
margin-bottom: 20px;
justify-content: center;
}
.filter-btn {
padding: 8px 20px;
border: 2px solid #e0e0e0;
background: white;
border-radius: 20px;
cursor: pointer;
transition: all 0.3s;
}
.filter-btn.active {
background: #667eea;
color: white;
border-color: #667eea;
}
.todo-list {
list-style: none;
}
.todo-item {
background: #f8f9fa;
padding: 15px;
margin-bottom: 10px;
border-radius: 10px;
display: flex;
align-items: center;
gap: 15px;
transition: transform 0.2s;
}
.todo-item:hover {
transform: translateX(5px);
}
.todo-item.completed .todo-text {
text-decoration: line-through;
opacity: 0.6;
}
.todo-checkbox {
width: 20px;
height: 20px;
cursor: pointer;
}
.todo-text {
flex: 1;
font-size: 16px;
}
.delete-btn {
background: #ff6b6b;
color: white;
border: none;
padding: 8px 15px;
border-radius: 5px;
cursor: pointer;
transition: background 0.3s;
}
.delete-btn:hover {
background: #ee5a52;
}
Step 3: JavaScript 로직 구현 (15분)
이제 핵심 기능을 구현하는 JavaScript 코드를 작성합니다:
// 상태 관리
let todos = JSON.parse(localStorage.getItem('todos')) || [];
let currentFilter = 'all';
// DOM 요소 선택
const todoInput = document.getElementById('todoInput');
const addBtn = document.getElementById('addBtn');
const todoList = document.getElementById('todoList');
const filterBtns = document.querySelectorAll('.filter-btn');
// 초기 렌더링
renderTodos();
// 이벤트 리스너
addBtn.addEventListener('click', addTodo);
todoInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') addTodo();
});
filterBtns.forEach(btn => {
btn.addEventListener('click', () => {
filterBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentFilter = btn.dataset.filter;
renderTodos();
});
});
// Todo 추가 함수
function addTodo() {
const text = todoInput.value.trim();
if (text === '') {
alert('할 일을 입력해주세요!');
return;
}
const newTodo = {
id: Date.now(),
text: text,
completed: false,
createdAt: new Date().toISOString()
};
todos.push(newTodo);
saveTodos();
renderTodos();
todoInput.value = '';
todoInput.focus();
}
// Todo 렌더링 함수
function renderTodos() {
const filteredTodos = getFilteredTodos();
todoList.innerHTML = '';
if (filteredTodos.length === 0) {
todoList.innerHTML = '할 일이 없습니다 😊 ';
return;
}
filteredTodos.forEach(todo => {
const li = document.createElement('li');
li.className = `todo-item ${todo.completed ? 'completed' : ''}`;
li.innerHTML = `
${todo.text}
`;
todoList.appendChild(li);
});
}
// 필터링 함수
function getFilteredTodos() {
switch(currentFilter) {
case 'active':
return todos.filter(todo => !todo.completed);
case 'completed':
return todos.filter(todo => todo.completed);
default:
return todos;
}
}
// Todo 완료 토글
function toggleTodo(id) {
todos = todos.map(todo =>
todo.id === id ? {...todo, completed: !todo.completed} : todo
);
saveTodos();
renderTodos();
}
// Todo 삭제
function deleteTodo(id) {
if (confirm('정말 삭제하시겠습니까?')) {
todos = todos.filter(todo => todo.id !== id);
saveTodos();
renderTodos();
}
}
// 로컬 스토리지 저장
function saveTodos() {
localStorage.setItem('todos', JSON.stringify(todos));
}
Step 4: 기능 테스트 (2분)
브라우저에서 index.html을 열어 다음 기능들을 테스트합니다:
- 새로운 할 일 추가 (Enter 키와 버튼 클릭 모두)
- 체크박스로 완료 상태 토글
- 삭제 버튼으로 항목 제거
- 필터 버튼으로 전체/진행중/완료 항목 보기
- 페이지 새로고침 후 데이터 유지 확인
테스트 및 배포
로컬 테스트
개발자 도구(F12)를 열어 콘솔 에러가 없는지 확인합니다. Application 탭에서 Local Storage를 확인하여 데이터가 올바르게 저장되는지 검증합니다. 다양한 브라우저(Chrome, Firefox, Safari)에서 테스트하여 호환성을 확인하세요.
배포 방법
완성된 Todo App을 무료로 배포하는 가장 쉬운 방법은 다음과 같습니다:
- GitHub Pages: 프로젝트를 GitHub 저장소에 push하고 Settings에서 Pages 활성화
- Netlify: 드래그 앤 드롭으로 즉시 배포 가능
- Vercel: GitHub 연동으로 자동 배포
배포 후 모바일 기기에서도 테스트하여 반응형 디자인이 잘 작동하는지 확인합니다. 이 30분만에 만드는 Todo App 완성 가이드를 통해 실제 배포까지 완료하면 포트폴리오에 추가할 수 있는 완성도 높은 프로젝트가 됩니다.
마무리 및 확장 아이디어
축하합니다! 30분 만에 완전히 작동하는 Todo App을 완성했습니다. 이 30분만에 만드는 Todo App 완성 가이드를 기반으로 다음과 같은 기능을 추가해볼 수 있습니다:
- 드래그 앤 드롭으로 할 일 순서 변경
- 중요도 표시 및 정렬 기능
- 마감일 설정 및 알림
- 카테고리/태그 시스템
- 다크 모드 지원
- 검색 기능
- 백엔드 API 연동 (Firebase, Supabase 등)
이 프로젝트를 통해 배운 DOM 조작, 이벤트 핸들링, 로컬 스토리지 활용 스킬은 더 복잡한 웹 애플리케이션 개발의 기초가 됩니다. 계속해서 기능을 추가하며 실력을 향상시켜보세요!
📚 함께 읽으면 좋은 글
30분만에 만드는 Todo App 완성 가이드 – 완성까지 한번에!
📅 2025. 10. 28.
🎯 30분만에 만드는 Todo App 완성 가이드
30분만에 만드는 Todo App 완성 가이드 – 완성까지 한번에!
📅 2025. 10. 21.
🎯 30분만에 만드는 Todo App 완성 가이드
30분만에 만드는 Todo App 완성 가이드 – 완성까지 한번에!
📅 2025. 10. 20.
🎯 30분만에 만드는 Todo App 완성 가이드
30분만에 만드는 Todo App 완성 가이드 – 완성까지 한번에!
📅 2025. 10. 15.
🎯 30분만에 만드는 Todo App 완성 가이드
30분만에 만드는 Todo App 완성 가이드 – 완성까지 한번에!
📅 2025. 10. 10.
🎯 30분만에 만드는 Todo App 완성 가이드
💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!
📢 이 글이 도움되셨나요? 공유해주세요!
여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨
🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏
💬 여러분의 소중한 의견을 들려주세요!
이 글을 읽고 새롭게 알게 된 정보가 있다면 공유해주세요!
⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨
🔔 블로그 구독하고 최신 글을 받아보세요!
🌟 프로젝트 아이디어부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨
📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!