# Todo Tutorial
*Build a complete todo application from scratch to learn essential Ivy concepts including [state management](../../03_Hooks/02_Core/03_UseState.md), [components](../02_Concepts/03_Widgets.md), and [event handling](../02_Concepts/07_EventHandlers.md).*
## Prerequisites
Before starting this tutorial, make sure you have [installed](02_Installation.md) Ivy.
## Creating the Todo App
Let's create a new todo app step by step.
### 1. Create a new project
Using the Ivy [CLI](../03_CLI/01_CLIOverview.md) we can create a new project.
```terminal
>ivy init --namespace Todos
```
### 2. Create the Todo Model
Create a new file `TodosApp.cs` in the `Apps` folder.
Declare a record `Todo.cs` to represent our todo items:
```csharp
public record Todo(string Title, bool Done);
```
### 3. Create the Main App Class
Create a new class `TodosApp` in the file that inherits from [ViewBase](../02_Concepts/02_Views.md):
```csharp
[App(icon: Icons.Calendar)]
public class TodosApp : ViewBase
{
public override object? Build()
{
// We'll add the implementation here
}
}
```
### 4. Add State Management
Inside the `Build` method, we'll add state management for our todos and input field:
```csharp
//State for the input field where users type new todo titles
var newTitle = UseState("");
//State for storing the list of todo items
var todos = UseState(ImmutableArray.Create<Todo>());
//Service for showing toast notifications
var client = UseService<IClientProvider>();
```
### 5. Build the UI
Now let's create the user interface. We'll use Ivy's [layout system](../../02_Widgets/02_Layouts/_Index.md) and components:
```csharp
return new Card().Title("Todos").Description("What do you want to get done today?")
| (Layout.Vertical()
| (Layout.Horizontal().Width(Size.Full())
| newTitle.ToTextInput(placeholder: "New Task...").Width(Size.Grow())
| new Button("Add", onClick: _ =>
{
var title = newTitle.Value;
todos.Set(todos.Value.Add(new Todo(title, false)));
client.Toast($"New '{title}' todo added.", "Todos");
newTitle.Set("");
}
).Icon(Icons.Plus).Variant(ButtonVariant.Primary)
)
| (Layout.Vertical()
| todos.Value.Select(todo => new TodoItem(todo,
() =>
{
todos.Set(todos.Value.Remove(todo));
},
() =>
{
todos.Set(todos.Value.Replace(todo, todo with
{
Done = !todo.Done
}));
}
))
))
;
```
### 6. Create the TodoItem Component
Create a new class `TodoItem.cs` for the todo item view:
```csharp
public class TodoItem(Todo todo, Action deleteTodo, Action toggleTodo) : ViewBase
{
public override object? Build()
{
return Layout.Vertical()
| (Layout.Horizontal().Align(Align.Center).Width(Size.Full())
| new BoolInput<bool>(todo.Done, _ =>
{
toggleTodo();
})
| (todo.Done
? Text.Muted(todo.Title).StrikeThrough().Width(Size.Grow())
: Text.Literal(todo.Title).Width(Size.Grow()))
| new Button(null, _ =>
{
deleteTodo();
}
).Icon(Icons.Trash).Variant(ButtonVariant.Outline)
)
| new Separator()
;
}
}
```
### 7. Run
Now let's run the project.
```terminal
>dotnet watch
```
You can find the source code for the app at [GitHub](https://github.com/Ivy-Interactive/Ivy-Framework/blob/main/Ivy.Samples.Shared/Apps/Demos/TodosApp.cs).