0
0
VueHow-ToBeginner · 4 min read

How to Create a Todo App in Vue: Simple Step-by-Step Guide

To create a todo app in Vue, use a ref to store the list of todos and the new todo input. Use v-for to display todos and v-model to bind input, then add new todos with a method triggered by a button click.
📐

Syntax

This is the basic structure for a Vue todo app:

  • ref holds reactive data like the todo list and input.
  • v-model binds input fields to data.
  • v-for loops over todos to display them.
  • @click triggers methods on button clicks.
vue
<template>
  <input v-model="newTodo" placeholder="Add todo" />
  <button @click="addTodo">Add</button>
  <ul>
    <li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li>
  </ul>
</template>

<script setup>
import { ref } from 'vue'

const todos = ref([])
const newTodo = ref('')

function addTodo() {
  if (newTodo.value.trim() === '') return
  todos.value.push({ id: Date.now(), text: newTodo.value })
  newTodo.value = ''
}
</script>
Output
An input box with an 'Add' button and a list below showing added todo items.
💻

Example

This example shows a complete Vue 3 todo app using the Composition API. You can type a todo, click Add, and see it appear below.

vue
<template>
  <main>
    <h1>Vue Todo App</h1>
    <input v-model="newTodo" placeholder="Enter a todo" aria-label="New todo input" />
    <button @click="addTodo" aria-label="Add todo">Add</button>
    <ul>
      <li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li>
    </ul>
  </main>
</template>

<script setup>
import { ref } from 'vue'

const todos = ref([])
const newTodo = ref('')

function addTodo() {
  if (!newTodo.value.trim()) return
  todos.value.push({ id: Date.now(), text: newTodo.value })
  newTodo.value = ''
}
</script>

<style scoped>
main {
  max-width: 400px;
  margin: 2rem auto;
  font-family: Arial, sans-serif;
}
input {
  padding: 0.5rem;
  font-size: 1rem;
  width: 70%;
  margin-right: 0.5rem;
}
button {
  padding: 0.5rem 1rem;
  font-size: 1rem;
  cursor: pointer;
}
ul {
  margin-top: 1rem;
  padding-left: 1rem;
}
li {
  margin-bottom: 0.5rem;
}
</style>
Output
A webpage with a heading 'Vue Todo App', an input box, an Add button, and a list that updates with each new todo entered.
⚠️

Common Pitfalls

Common mistakes include:

  • Not using ref for reactive data, so UI doesn't update.
  • Forgetting to clear the input after adding a todo.
  • Not checking for empty input before adding.
  • Missing :key in v-for, which can cause rendering issues.
vue
<!-- Wrong: No reactive refs and no input clearing -->
<template>
  <input v-model="newTodo" />
  <button @click="addTodo">Add</button>
  <ul>
    <li v-for="todo in todos">{{ todo }}</li>
  </ul>
</template>

<script setup>
let todos = []
let newTodo = ''
function addTodo() {
  todos.push(newTodo)
  // input not cleared
}
</script>

<!-- Right: Use ref, clear input, and add key -->
<template>
  <input v-model="newTodo" />
  <button @click="addTodo">Add</button>
  <ul>
    <li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li>
  </ul>
</template>

<script setup>
import { ref } from 'vue'
const todos = ref([])
const newTodo = ref('')
function addTodo() {
  if (!newTodo.value.trim()) return
  todos.value.push({ id: Date.now(), text: newTodo.value })
  newTodo.value = ''
}
</script>
📊

Quick Reference

Remember these key Vue features for a todo app:

FeaturePurpose
refCreates reactive data variables
v-modelBinds input fields to reactive data
v-forLoops over arrays to render lists
@clickHandles user click events
:keyProvides unique keys for list items

Key Takeaways

Use Vue's ref to create reactive todo list and input variables.
Bind input with v-model and display todos with v-for and :key.
Always check for empty input and clear it after adding a todo.
Use @click to trigger adding todos on button press.
Include accessibility attributes like aria-label for better usability.