Build A Simple Todo App Using Microsoft Fluent UI React

This is the second article in the Fluent UI React series. In this article, we will be creating a simple Todo application using React JS and Fluent UI React library. We will be exploring so many Fluent UI components like Stack, Dialog, etc. So let's grab a cup of coffee and start coding.
 

TL;DR

Prerequisites
 
You need to have installed the latest stable version of Node JS and NPM. You will easily understand the following tutorial if you have a basic understanding of,
  • HTML, CSS, and JavaScript
  • React JS, Hooks 
If you don't know about Microsoft Fluent UI you can check out my article: Getting Started With Microsoft Fluent UI React
 

Building Todo Application

 
Create new React App
 
We will be using the Create React App tool to create our React app. So let's run the below command:
  1. npx create-react-app fluent-ui-todo-app --typescript  
Integrate Fluent UI React into App
 
Now once the app is successfully created then the next step is to install Fluent React into our app. 
  1. cd fluent-ui-todo-app  
  2. npm i @fluentui/react  
Building components for App
 
We will be creating a simple todo application where we can add new todo and delete the existing todos. So we know that everything in React is component so we will be dividing our todo app into 3 components; i.e AddTodo, TodoList, TodoItem. The great thing is we will using different Fluent UI components while creating these components.
 
To enable Fluent UI style we have to add Fabric component from Fluent UI library so open `index.tsx` file and add the below code,
  1. import React from 'react';  
  2. import ReactDOM from 'react-dom';  
  3. import './index.css';  
  4. import App from './App';  
  5. import * as serviceWorker from './serviceWorker';  
  6. import { Fabric } from "@fluentui/react";  
  7.   
  8. ReactDOM.render(  
  9.   <React.StrictMode>  
  10.     <Fabric>  
  11.       <App />  
  12.     </Fabric>  
  13.   </React.StrictMode>,  
  14.   document.getElementById('root')  
  15. );  
  16.   
  17. serviceWorker.unregister();   
To organize our components, we are going to use Stack Utility of Fluent UI. According to doc,
 
A Stack is a container-type component that abstracts the implementation of a flexbox in order to define the layout of its children components.
 
Stack is based on flexbox so we can control,
  • Direction: By adding vertical or horizontal properties, 
  • Alignment: using verticalAlign and horizontalAlign` properties,
  • Spacing: by adding gap and verticleGap properties.
 So open App.tsx file add below code:
  1. import React from 'react';  
  2. import './App.css';  
  3. import { Stack } from "@fluentui/react";  
  4.   
  5. function App() {  
  6.   return (  
  7.     <div className="wrapper">  
  8.       <Stack horizontalAlign="center">  
  9.         <h1>Todo App using Fluent UI & React</h1>  
  10.         <Stack style={{ width: 300 }} gap={25}>  
  11.           Add todo component...  
  12.           TodoList componets...  
  13.         </Stack>  
  14.       </Stack>  
  15.     </div>  
  16.   );  
  17. }  
  18.   
  19. export default App;  
 Add the below class into App.css file,
  1. .wrapper {    
  2.   max-width: 480px;    
  3.   margin: auto;    
  4.   background: #fff;    
  5.   margin-top: 50px;    
  6.   display: flex;    
  7.   flex-direction: column;    
  8.   padding-left: 50px;    
  9.   padding-right: 50px;    
  10.   padding-bottom: 50px;    
  11. }     
We will start by displaying the todo list. First, we will use useState() hook to in the App component which stores an initial list of Todos. So add the below line App component: 
  1. const [todos, setTodos] = useState([{ id: 1, name: "Todo Item 1" }, { id: 2, name: "Todo Item 2" }]);  
Now the next step is to display this Todo list. So to do this create 2 components, TodoItem for single todo and TodoList which uses the TodoItem component to display all the todos by using the map() method.
 
To create TodoItem component add the below code,
  1. import React from 'react';  
  2. import { Stack, Label } from '@fluentui/react';  
  3.   
  4. function TodoItem(props: any) {  
  5.     return (  
  6.         <Stack>  
  7.             <Stack horizontal verticalAlign="center" horizontalAlign="space-between">  
  8.                 <Label>{props.todo.name}</Label>  
  9.             </Stack>  
  10.         </Stack>  
  11.     );  
  12. }  
  13.   
  14. export default TodoItem  
So here we have used Stack for organizing the Todo and Label to show the todo name from @fluentui/react.
 
Create TodoList component add below code,
  1. import React from 'react';  
  2. import { Stack, Label } from "@fluentui/react";  
  3. import TodoItem from './TodoItem';  
  4.   
  5. function TodoList(props:any) {  
  6.   
  7.     return (  
  8.         <Stack gap={10} >  
  9.             { props.todos.length > 0 ? props.todos.map((todo: any) => (  
  10.                 <TodoItem todo={todo} key={todo.id}/>  
  11.             )):   
  12.             <Label>Todo list is empty...</Label>}  
  13.         </Stack>  
  14.     );  
  15. }  
  16.   
  17. export default TodoList;  
Now we have to import the TodoList component into App component and pass the todos present in the App component state as props to TodoList. 
  1. import React, { useState } from 'react';  
  2. import './App.css';  
  3. import { Stack } from "@fluentui/react";  
  4. import TodoList from './components/TodoList';  
  5.   
  6. function App() {  
  7.   const [todos, setTodos] = useState([{ id: 1, name: "Todo Item 1" }, { id: 2, name: "Todo Item 2" }]);  
  8.   return (  
  9.     <div className="wrapper">  
  10.       <Stack horizontalAlign="center">  
  11.         <h1>Todo App using Fluent UI & React</h1>  
  12.         <Stack style={{ width: 300 }} gap={25}>  
  13.           <TodoList todos={todos} />  
  14.         </Stack>  
  15.       </Stack>  
  16.     </div>  
  17.   );  
  18. }  
  19.   
  20. export default App;  
So run the app and you will see the Todo's list.
 
 
So the next step is to add new todo functionality. Create a new component called AddTodo which has one input field and one button. On the button click to call a function in props to add todo.
  1. import React, { useState } from 'react';  
  2. import { Stack,TextField, PrimaryButton } from "@fluentui/react";  
  3.   
  4. function AddTodo(props:any) {  
  5.     const [todoName, setTodoName] = useState("");      
  6.     const addTodo = () => {        
  7.         props.addTodo(todoName);  
  8.         setTodoName("");  
  9.     }  
  10.     const setTodo = (e: any) =>{  
  11.         setTodoName(e.target.value);  
  12.     }  
  13.   
  14.     return (  
  15.         <Stack>  
  16.             <Stack horizontal >  
  17.                 <Stack.Item grow>  
  18.                     <TextField placeholder="Add new item" value={todoName} onChange={setTodo }/>  
  19.                 </Stack.Item>  
  20.                 <PrimaryButton onClick={addTodo} >Add</PrimaryButton>  
  21.             </Stack>  
  22.         </Stack>  
  23.     );  
  24. }  
  25.   
  26. export default AddTodo;  
Here we have used `TextField`component to display an input field and `PrimaryButton` for displaying button from `@fluentui/react`. Create a new function in App component for adding todo into state and pass it to AddTodo function in props.
  1. import React, { useState } from 'react';  
  2. import './App.css';  
  3. import { Stack } from "@fluentui/react";  
  4. import TodoList from './components/TodoList';  
  5. import AddTodo from './components/AddTodo';  
  6.   
  7. function App() {  
  8.   const [todos, setTodos] = useState([{ id: 1, name: "Todo Item 1" }, { id: 2, name: "Todo Item 2" }]);  
  9.   
  10.   const addTodo = (todoName: string) => {  
  11.     if (todoName != "") {  
  12.       const newId = todos.length + 1;  
  13.       const newTodos = [...todos, { id: newId, name: todoName }];  
  14.       setTodos(newTodos);  
  15.     }  
  16.   };  
  17.   
  18.   return (  
  19.     <div className="wrapper">  
  20.       <Stack horizontalAlign="center">  
  21.         <h1>Todo App using Fluent UI & React</h1>  
  22.         <Stack style={{ width: 300 }} gap={25}>  
  23.           <AddTodo addTodo={addTodo} />  
  24.           <TodoList todos={todos} />  
  25.         </Stack>  
  26.       </Stack>  
  27.     </div>  
  28.   );  
  29. }  
  30.   
  31. export default App;  
 
 
Final step is to delete the todo in the list. So first add deleteTodo function in the App component as below,
  1. const deleteTodo = (id: number) => {  
  2.     const newTasks = todos.filter((todo) => { return todo.id !== id });  
  3.     setTodos(newTasks);  
  4.   };   
and pass this function to TodoList component,
  1. <div className="wrapper">  
  2.       <Stack horizontalAlign="center">  
  3.         <h1>Todo App using Fluent UI & React</h1>  
  4.         <Stack style={{ width: 300 }} gap={25}>  
  5.           <AddTodo addTodo={addTodo} />  
  6.           <TodoList todos={todos} deleteTodo={deleteTodo} />  
  7.         </Stack>  
  8.       </Stack>  
  9.     </div>  
Again from TodoList component pass this deleteTodo function TodoItem component,
  1. <TodoItem todo={todo} key={todo.id} deleteTodo={props.deleteTodo} />  
We will be using IconButton for showing delete button for each todo and also using Dialog Component to ask user before deleting todo. So deleteTodo component looks like this,
  1. import React, { useState } from 'react';  
  2. import { Stack, Label, IconButton, Dialog, DialogFooter, DefaultButton, PrimaryButton, DialogType } from '@fluentui/react';  
  3.   
  4. function TodoItem(props: any) {  
  5.     const [openDeleteModal, setOpenModal] = useState(true);  
  6.   
  7.     const deleteTodo = (id: number) => {  
  8.         props.deleteTodo(id);  
  9.         setOpenModal(true);  
  10.     }  
  11.   
  12.     return (  
  13.         <Stack>  
  14.             <Stack horizontal verticalAlign="center" horizontalAlign="space-between">  
  15.                 <Label>{props.todo.name}</Label>  
  16.                 <IconButton iconProps={{ iconName: 'trash' }} className="clearButton" onClick={() => { setOpenModal(!openDeleteModal) }} />  
  17.             </Stack>  
  18.             <Dialog  
  19.                 hidden={openDeleteModal}  
  20.                 dialogContentProps={{  
  21.                     type: DialogType.normal,  
  22.                     title: "Delete",  
  23.                     subText:  
  24.                         "Are you sure you want to delete this item? This cannot be undone."  
  25.                 }}  
  26.                 modalProps={{  
  27.                     isBlocking: false  
  28.                 }}  
  29.             >  
  30.                 <DialogFooter>  
  31.                     <PrimaryButton text="Yes" onClick={() => { deleteTodo(props.todo.id) }} />  
  32.                     <DefaultButton text="No" onClick={() => { setOpenModal(true) }} />  
  33.                 </DialogFooter>  
  34.             </Dialog>  
  35.         </Stack>  
  36.     );  
  37. }  
  38.   
  39. export default TodoItem  
Maintain a state of dialog like when to open and when to close by using useState() hook. You can check more properties about Dialog here. To enable icons we have to import `initializeIcons` from Fluent UI and call `initializeIcons()` method so open index.tsx and `initializeIcons` in it.
  1. import React from 'react';  
  2. import ReactDOM from 'react-dom';  
  3. import './index.css';  
  4. import App from './App';  
  5. import * as serviceWorker from './serviceWorker';  
  6. import { Fabric, initializeIcons } from "@fluentui/react";  
  7.   
  8. initializeIcons();  
  9.   
  10. ReactDOM.render(  
  11.   <React.StrictMode>  
  12.     <Fabric>  
  13.       <App />  
  14.     </Fabric>  
  15.   </React.StrictMode>,  
  16.   document.getElementById('root')  
  17. );  
  18.   
  19. serviceWorker.unregister();  
 

Deploy it

 
We can now deploy our application on any hosting platform. I recommend deploying it on Netlify because it supports project structures like this and can quickly create deployments. You can deploy application on Now or Surge also.  
 

Conclusion

 
In this article, I have demonstrated to you how to create a Todo application using Fluent UI React. We have also used a few Fluent UI React components like Stack, Dialog, PrimaryButton, Label, TextField.
 
I really hope that you enjoyed this little app, and please do not hesitate to send me your thoughts or comments about what could I have done better.
 
You can reach out to me on twitter @sumitkharche01
 
Happy Coding!!