Todo App using VueJS 3 Composition API and Tailwind CSS
Searching for “Simple Todo App tutorial using Composition API” ?
You’re in a right place :D
Don’t be afraid by seeing “Tailwind CSS”. Its just a makeup as not to make it look like my ugly face.
This is the very easiest tutorial which is neither going to confuse you, nor going to make you go mad.
Highly self explainable code and totally from scratch. From setting up till finishing and wrapping up.
Pre-requisites:
- You must know how to use Computer :P.
- Overview of VueJS 3 is enough. You don’t need to be a Guru.
- No need of Tailwind CSS Experience. If you understand CSS Classes, that would be enough.
- Any text editor will do except Vim, Nano or MS Notepad.
Actual App Demo
Step 1: Create a Folder
Create a folder, inside which we will be creating our project.
For this tutorial, I created a new folder named “Vue Todo” on desktop.
Step 2: Install Vue CLI
Go inside “Vue Todo” folder and open “cmd” in this location.
Install Vue CLI by typing in your command or terminal:
npm install -g @vue/cli
Note: You might see some warning messages. Don’t worry, just ignore them.
Wait for the process to finish.
Step 3: Create a new VueJS Project
After Step 1 completes, create a new VueJS Project by typing the following command and wait for the process to finish:
vue create todo
Step 4: Select Vue 3
Step 5: Run the Project
Get inside the folder
cd todo
Run the project
npm run serve
Open the link in browser : http://localhost:8080/
Leave it running on the browser.
Step 6: Setting up the Project
Delete the folder as marked in red box in the screenshot below.
Step 7: Write this code in “App.vue” file
<template>
<div>
<h1>Todo List</h1>
<form>
<input />
<button>Add Todo</button>
<button>Remove All Todos</button>
</form>
</div>
<div>
<h1>Done Homework</h1>
<h1 class="completed">Riding a Bicycle</h1>
</div>
</template><script setup></script><style>
.completed
{
text-decoration: line-through;
}
</style>
Let’s take a peek in a browser :
Step 8: Time for JavaScripts
Inside <script setup></script> tag in “App.vue”, add the JavaScript Code below :
import { ref } from "vue";const newTodo = ref("");
const todos = ref([]);function addTodo() {
if(newTodo.value !== "") {
todos.value.push({ complete: false, text: newTodo.value });
newTodo.value = "";
}
}function removeAllTodos() {
todos.value.splice(0, todos.value.length);
}
function completedTodo(todo) {
todo.complete = !todo.complete;
}
Step 9: Let’s get it Working
Replace the Markup part of the code inside <template></template> tag in “App.vue”:
<div>
<h1>Todo List</h1> <form @submit.prevent="addTodo()">
<input v-model="newTodo" />
<button>Add Todo</button>
<button
v-if="todos.length !== 0"
@click="removeAllTodos"
>
Remove All Todos
</button>
</form>
</div><div>
<h1 :class="{ completed: todo.complete }"
v-for="(todo, index) in todos"
:key="index"
@click="completedTodo(todo)"
>
{{ todo.text }}
</h1>
</div>
Again, let’s take a peek in a browser :
Yay! We made it.
Here’s the full code of “App.vue”
<template>
<div>
<h1>Todo List</h1> <form @submit.prevent="addTodo()">
<input v-model="newTodo" />
<button>Add Todo</button>
<button
v-if="todos.length !== 0"
@click="removeAllTodos"
>
Remove All Todos
</button>
</form>
</div> <div>
<h1 :class="{ completed: todo.complete }"
v-for="(todo, index) in todos"
:key="index"
@click="completedTodo(todo)"
>
{{ todo.text }}
</h1>
</div>
</template><script setup>
import { ref } from "vue"; const newTodo = ref("");
const todos = ref([]); function addTodo() {
if(newTodo.value !== "") {
todos.value.push({
complete: false, text: newTodo.value
});
newTodo.value = "";
}
} function removeAllTodos() {
todos.value.splice(0, todos.value.length);
} function completedTodo(todo) {
todo.complete = !todo.complete;
}
</script><style>
.completed
{
text-decoration: line-through;
}
</style>
Looks Ugly ? Huh!
Let’s give this beauty a touch of Tailwind CSS.
Step 10: Install Tailwind CSS
Open a new command window inside your project folder and then execute this 2 commands one by one:
> npm install -D tailwindcss postcss autoprefixer
> npx tailwindcss init -p
Step 11: Configure “tailwind.config.js” file
Replace the contents of “tailwind.config.js” with the code below:
module.exports = {
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
Step 12: Create stylesheet
Create a new file “styles.css” under “assets” folder and add the code below:
@tailwind base;
@tailwind components;
@tailwind utilities;
Step 13: Include the “styles.css” to your Vue Project
Replace the contents of “main.js” with the code below:
import { createApp } from 'vue'
import App from './App.vue'
import './assets/styles.css'createApp(App).mount('#app')
Step 15: Finally, we’re in last step to styling :D
Again, replace the Markup part of the code inside <template></template> tag in “App.vue”:
<div class="container mx-auto px-10 md:px-0">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div></div>
<div>
<div class="mt-10">
<h1 class="text-5xl font-semibold text-gray-600">Todo List</h1> <div class="mt-6">
<form @submit.prevent="addTodo()">
<div class="grid grid-cols-1 gap-4">
<div>
<input class="border-2 outline-none py-2 px-2 shadow-md font-medium w-full rounded border-blue-300 hover:border-blue-600 focus:border-blue-600 focus:shadow-blue-200" v-model="newTodo" />
</div>
<div>
<div class="grid grid-cols-2 gap-2">
<div>
<button class="text-white py-2 px-4 shadow-md w-full rounded bg-red-400 hover:bg-red-600 font-semibold" v-if="todos.length !== 0" @click="removeAllTodos">Remove All Todos</button>
</div>
<div>
<button class="text-white py-2 px-4 shadow-md w-full rounded bg-blue-400 hover:bg-blue-600 font-semibold">Add Todo</button>
</div>
</div>
</div>
</div>
</form>
</div> <div class="mt-8 text-center">
<div class="grid grid-cols-1 gap-3">
<div>
<div class="h-full" v-if="todos.length === 0">
<p class="text-gray-400">It appears you didn't added any To-Do.</p>
</div>
</div>
<div class="rounded shadow-md p-3 h-full hover:shadow-gray-400 text-gray-600 text-lg font-semibold" :class="{ completed: todo.complete }" v-for="(todo, index) in todos" :key="index" @click="completedTodo(todo)">
<span class="text-gray-600 text-lg font-semibold">{{ todo.text }}</span>
</div>
</div>
</div>
</div>
</div>
<div></div>
</div>
</div>
Again, let’s take a peek in a browser :
Yes! Yes! Yes! We did it.
You made an App in VueJS 3 using Composition API.
A Little Extra for Extra Features
We did made a Todo App, but let’s use some Local-Storage feature to make the data persistent even after you close the browser.
To make it happen, just Replace the code inside the <script setup></script> in “App.vue” with the code below:
import { ref } from "vue";const newTodo = ref("");let storedTodos;localStorage.getItem("todos") ? storedTodos = JSON.parse(localStorage.getItem("todos")) : (storedTodos = []);const todos = ref(storedTodos);function addTodo() {
if(newTodo.value !== "") {
todos.value.push({ complete: false, text: newTodo.value });
newTodo.value = "";
}
}function removeAllTodos() {
todos.value.splice(0, todos.value.length);
updateStorage();
}function completedTodo(todo) {
todo.complete = !todo.complete;
updateStorage();
}function updateStorage() {
localStorage.setItem('todos', JSON.stringify(todos.value));
}
Hope you like the tutorial :D
Here’s the Github Repository link: https://github.com/sayansinha5/VueJS-3-TodoList