확인한 환경과 범위

Chromium 156.0.8078.74. 본문의 HTML·CSS·JavaScript를 실제 브라우저로 렌더링하고 현재 화면을 캡처했습니다. 모든 조작·레이아웃·접근성을 검증한 것은 아닙니다.

이 글의 순서 6개 단락

이번에 만들 기능

지난 단계에서는 입력한 할 일을 목록에 추가했습니다. 이번에는 새로 추가되는 각 항목에 삭제 버튼을 붙입니다. 버튼을 누르면 그 버튼이 들어 있는 항목 하나만 사라지도록 만들겠습니다.

아래 완성 예제에는 앞 단계에서 만든 입력값 검사와 항목 추가 기능도 들어 있습니다. 이전 파일이 없어도 세 파일을 같은 폴더에 저장하면 시작할 수 있습니다.

항목과 버튼 만들기

할 일을 추가할 때 li 요소와 button 요소를 만듭니다. 할 일 글자는 별도의 span에 textContent로 넣습니다. 이렇게 하면 입력한 글자가 HTML 태그로 해석되지 않고 텍스트로 표시됩니다.

const item = document.createElement('li');
const text = document.createElement('span');
const deleteButton = document.createElement('button');

text.textContent = title;
deleteButton.type = 'button';
deleteButton.textContent = '삭제';

item.append(text, deleteButton);

append()는 텍스트 요소와 버튼을 차례로 li 안에 넣습니다. 버튼의 type을 button으로 지정하면 나중에 버튼이 폼 안에 놓이더라도 기본 제출 버튼으로 동작하지 않습니다.

누른 버튼에 연결된 항목 지우기

각 항목을 만들 때 삭제 버튼에도 클릭 이벤트를 연결합니다.

deleteButton.addEventListener('click', () => {
  item.remove();
});

이 함수가 사용하는 item은 해당 버튼을 만들 때 함께 만든 li입니다. 따라서 버튼을 눌렀을 때 목록 전체가 아니라 그 버튼이 속한 항목만 제거합니다. 같은 과정을 새 할 일마다 반복하므로 각 버튼이 자기 항목을 삭제합니다.

완성 코드

다음 세 파일을 같은 폴더에 저장하고 index.html을 브라우저에서 여세요. defer 덕분에 JavaScript 파일은 HTML을 읽는 동안 내려받고, 문서 분석이 끝난 뒤 실행됩니다.

index.html

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>할 일 목록</title>
  <link rel="stylesheet" href="style.css">
  <script src="script.js" defer></script>
</head>
<body>
  <main class="todo-app">
    <h1>할 일 목록</h1>
    <div class="input-row">
      <label for="todo-input">할 일</label>
      <input id="todo-input" type="text" placeholder="할 일을 입력하세요">
      <button id="add-button" type="button">추가</button>
    </div>
    <p id="message" role="status"></p>
    <ul id="todo-list" aria-label="할 일 목록"></ul>
  </main>
</body>
</html>

style.css

body {
  margin: 0;
  padding: 24px;
  background: #f3f6fb;
  color: #172033;
  font-family: sans-serif;
}

.todo-app {
  max-width: 520px;
  margin: 0 auto;
  padding: 24px;
  background: white;
  border-radius: 12px;
}

.input-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

input {
  flex: 1 1 180px;
  min-width: 0;
  padding: 8px;
}

button {
  padding: 8px 12px;
  cursor: pointer;
}

#message {
  min-height: 1.5em;
  color: #a22b2b;
}

#todo-list {
  padding: 0;
  list-style: none;
}

#todo-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid #dce3ed;
}

#todo-list li span {
  overflow-wrap: anywhere;
}

script.js

const input = document.querySelector('#todo-input');
const addButton = document.querySelector('#add-button');
const list = document.querySelector('#todo-list');
const message = document.querySelector('#message');

addButton.addEventListener('click', () => {
  const title = input.value.trim();

  if (title === '') {
    message.textContent = '할 일을 입력해 주세요.';
    return;
  }

  message.textContent = '';

  const item = document.createElement('li');
  const text = document.createElement('span');
  const deleteButton = document.createElement('button');

  text.textContent = title;
  deleteButton.type = 'button';
  deleteButton.textContent = '삭제';
  deleteButton.setAttribute('aria-label', `${title} 삭제`);

  deleteButton.addEventListener('click', () => {
    item.remove();
  });

  item.append(text, deleteButton);
  list.append(item);
  input.value = '';
  input.focus();
});

aria-label은 각 삭제 버튼에 할 일 이름을 포함한 접근 가능한 이름을 지정합니다. 화면에는 간단히 ‘삭제’가 표시되지만 보조 기술로는 어떤 항목을 삭제하는 버튼인지 구분할 수 있습니다.

아래 이미지는 할 일을 추가하기 전의 초기 화면입니다. 입력과 삭제 동작은 다음 순서에 따라 직접 확인해 보세요.

각 할 일에 삭제 버튼 붙이기 — 첫 예제의 실제 실행 결과

직접 확인하기

  1. 책 읽기, 산책하기, 물 마시기를 차례로 추가합니다.
  2. 가운데 항목의 삭제 버튼을 누릅니다. 산책하기만 사라지고 나머지 두 항목은 남아 있어야 합니다.
  3. 남은 항목 중 하나를 삭제한 뒤 새 항목을 추가하고, 새 항목의 삭제 버튼도 눌러 봅니다.
  4. 공백만 입력하고 추가 버튼을 눌러 안내 문구가 나타나는지도 확인합니다.

버튼이 동작하지 않으면 개발자 도구 콘솔의 오류를 확인하고, 세 파일이 같은 폴더에 있는지와 파일 이름이 HTML의 경로와 일치하는지 살펴보세요.

연습

같은 이름의 할 일을 두 개 추가한 뒤 한쪽의 삭제 버튼을 눌러 보세요. 이름이 같아도 클릭한 버튼이 속한 항목 하나만 사라지는지 확인합니다. 이어서 삭제 버튼의 화면 문구를 지우기로 바꿔 보고, 이벤트가 여전히 동작하는지도 살펴보세요.

다음 강의에서는 항목 수와 빈 목록 안내를 추가하고, 항목을 추가하거나 삭제할 때 화면 상태를 갱신합니다.

한 줄씩 이해하고, 차곡차곡 기록합니다.이 글의 오류 제보하기 ↗