DEV Community

Mike Teddy Omondi
Mike Teddy Omondi

Posted on • Updated on

 

Building a Todo App using SvelteKit Made Easy

Example image

Here we create an application with simple functionality of creating, reading, updating and deleting a completed task.

Svelte is the most loved front-end library as of 2022 .

Creating a Svelte project

To initialise a Svelte project, run the command

# create a new project in the current directory
npm init svelte@next

# create a new project in my-app
npm init svelte@next todo-svelte-app
Enter fullscreen mode Exit fullscreen mode

Note: the @next is temporary version and will be updated in the future.

Allow eslint and prettier configuration while initialising the project.

Adding & configuring Tailwind CSS

Install the packages required as dev-dependencies because they will only be used in development and also to build the css bundle for production

npm i -D tailwindcss@latest postcss@latest autoprefixer@latest
Enter fullscreen mode Exit fullscreen mode

Create a post.config.cjs file in the root directory and set up with the following configuration

module.exports = {
    plugins: {
        tailwindcss: {},
        autoprefixer: {}
    }
};
Enter fullscreen mode Exit fullscreen mode

Next is to run the npx tailwindcss init initialise the tailwind.config.js file in the root directory and add the following configurations

module.exports = {
    purge: ['./src/**/*.svelte', './src/**/*.css'],
    darkMode: false, // or 'media' or 'class'
    content: [],
    theme: {
        extend: {}
    },
    plugins: []
};
Enter fullscreen mode Exit fullscreen mode

Create app.css file in the src directory and add the following configurations

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

Additional Libraries

We will install an additional library to create unique ids for our todos.

# Installs as a main dependency
npm install -S uuid
Enter fullscreen mode Exit fullscreen mode

Creating the app

Main Layout file

We need to create another file under src/routes directory called __layout.svelte and add the following code

<script>
    // Importing the app.css
    import '../app.css';
</script>

<div class="container mx-auto my-6 max-w-lg">
    <slot />
</div>

Enter fullscreen mode Exit fullscreen mode

Stores

Svelte frontend framework uses the idea of stores to maintain state throughout the app. So we'll create a stores directory and in it create a todoStore.js file and then add the following code:

import { v4 } from 'uuid';
import { writable } from 'svelte/store';

export const todos = writable([]);

export const addTodo = (text) => {
    todos.update((cur) => {
        const newTodos = [...cur, { id: v4(), text, completed: false, createdAt: Date.now() }];
        return newTodos;
    });
};

export const deleteTodo = (id) => {
    todos.update((todos) => todos.filter((todo) => todo.id !== id));
};

export const completeTodo = (id) => {
    todos.update((todos) => {
        let index = -1;
        for (let i = 0; i < todos.length; i++) {
            if (todos[i].id === id) {
                index = i;
                break;
            }
        }
        if (index !== -1) {
            todos[index].completed = !todos[index].completed;
        }
        return todos;
    });
};

Enter fullscreen mode Exit fullscreen mode

Components

Our app will have two components: one for the form and another for the unordered list component. Create another directory named components under src directory and add TodoForm.svelte and Todo.svelte files

In the TodoForm.svelte file add:

<script>
    import { addTodo } from '../stores/todoStore.js';
    let todo = '';
    const handleSubmit = () => {
        // console.log('Submitting...');
        if (todo === '') {
            todo = '';
            return alert('Please enter a todo as required!');
        }
        addTodo(todo);
        todo = '';
    };
</script>

<form class="my-6 mx-3" on:submit|preventDefault={handleSubmit}>
    <div class="flex flex-col text-sm mb-2">
        <label for="todo" class="font-bold mb-2 text-gray-800">Todo:</label>
        <input
            type="text"
            name="todo"
            bind:value={todo}
            placeholder="What's on your mind?"
            class="appearance-none shadow-sm border border-gray-200 p-2 focus:outline-none focus:border-gray-500 rounded-lg"
        />
    </div>
    <button
        type="submit"
        class="w-full shadow-sm rounded bg-blue-500 hover:bg-blue-600 text-white py-2 px-4">Add</button
    >
</form>

Enter fullscreen mode Exit fullscreen mode

In the Todo.svelte file add:

<script>
    import { deleteTodo, completeTodo } from '../stores/todoStore.js';
    export let todo;
</script>

<li
    class="bg-white flex items-center shadow-sm border border-gray-200 rounded-md my-2 mx-3 py-2 px-4"
>
    <input
        name="completed"
        type="checkbox"
        checked={todo.completed}
        on:change={() => completeTodo(todo.id)}
        class="mr-2 form-checkbox h-5 w-5"
    />
    <span class={`flex-1 text-gray-800 ${todo.completed ? 'line-through' : ''}`}>{todo.text}</span>
    {#if todo.completed}
        <button
            type="button"
            class="text-sm bg-red-500 hover:bg-red-600 text-white py-1 px-2 rounded focus:outline-none focus:shadow-outline"
            on:click={() => deleteTodo(todo.id)}>Delete</button
        >
    {/if}
</li>

Enter fullscreen mode Exit fullscreen mode

Our index.svelte should then be modified to:

<script>
    import TodoForm from '../components/TodoForm.svelte';
    import Todo from '../components/Todo.svelte';
    import { todos } from '../stores/todoStore.js';
</script>

<main>
    <h1 class="text-2xl font-bold text-center text-gray-800 md:text-3xl">Todo App</h1>
    <TodoForm />
    {#each $todos as todo}
        <Todo {todo} index={todo.id} />
    {/each}
</main>

Enter fullscreen mode Exit fullscreen mode

Running the project

To run the project, execute this command as from the script in the Node's package.json file; open the browser on http://localhost:3000 and voila! you created your todo app using sveltekit.

npm run dev
Enter fullscreen mode Exit fullscreen mode

Conclusion

To wrap up this tutorial, I am linking the code in my GitHub here for you to fork or clone. To expand on this I will create another part of this tutorial where we will add authentication with json web tokens (JWT) provided by another RESTful API with either Express, Flask or Django. Hit me up on my Twitter or LinkedIn to suggest what you would want to see next or comment below on this tutorial.

References:

Top comments (3)

Collapse
 
steve_upton_d5d8acc40a932 profile image
Steve Upton

What’s up with the random “Svelte is the most dreaded library as of 2022” below the opening paragraph? Stack Overflow’s 2021 developers survey puts Svelte squarely in first place as the most LOVED framework, so this is really confusing, almost like this was a copy and paste error.

Collapse
 
miketeddyomondi profile image
Mike Teddy Omondi • Edited

It is dreaded by the way...because of its ease of use. It's no copy-paste error

Collapse
 
gudata profile image
gudata

Hello,
for what you use postcss ?

Visualizing Promises and Async/Await 🤯

async await

☝️ Check out this all-time classic DEV post