- HTML, CSS, and JavaScript
- React JS, Hooks
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:
- 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.
- cd fluent-ui-todo-app
- 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,
- import React from 'react';
- import ReactDOM from 'react-dom';
- import './index.css';
- import App from './App';
- import * as serviceWorker from './serviceWorker';
- import { Fabric } from "@fluentui/react";
-
- ReactDOM.render(
- <React.StrictMode>
- <Fabric>
- <App />
- </Fabric>
- </React.StrictMode>,
- document.getElementById('root')
- );
-
- 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:
- import React from 'react';
- import './App.css';
- import { Stack } from "@fluentui/react";
-
- function App() {
- return (
- <div className="wrapper">
- <Stack horizontalAlign="center">
- <h1>Todo App using Fluent UI & React</h1>
- <Stack style={{ width: 300 }} gap={25}>
- Add todo component...
- TodoList componets...
- </Stack>
- </Stack>
- </div>
- );
- }
-
- export default App;
Add the below class into App.css file,
- .wrapper {
- max-width: 480px;
- margin: auto;
- background: #fff;
- margin-top: 50px;
- display: flex;
- flex-direction: column;
- padding-left: 50px;
- padding-right: 50px;
- padding-bottom: 50px;
- }
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:
- 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,
- import React from 'react';
- import { Stack, Label } from '@fluentui/react';
-
- function TodoItem(props: any) {
- return (
- <Stack>
- <Stack horizontal verticalAlign="center" horizontalAlign="space-between">
- <Label>{props.todo.name}</Label>
- </Stack>
- </Stack>
- );
- }
-
- 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,
- import React from 'react';
- import { Stack, Label } from "@fluentui/react";
- import TodoItem from './TodoItem';
-
- function TodoList(props:any) {
-
- return (
- <Stack gap={10} >
- { props.todos.length > 0 ? props.todos.map((todo: any) => (
- <TodoItem todo={todo} key={todo.id}/>
- )):
- <Label>Todo list is empty...</Label>}
- </Stack>
- );
- }
-
- 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.
- import React, { useState } from 'react';
- import './App.css';
- import { Stack } from "@fluentui/react";
- import TodoList from './components/TodoList';
-
- function App() {
- const [todos, setTodos] = useState([{ id: 1, name: "Todo Item 1" }, { id: 2, name: "Todo Item 2" }]);
- return (
- <div className="wrapper">
- <Stack horizontalAlign="center">
- <h1>Todo App using Fluent UI & React</h1>
- <Stack style={{ width: 300 }} gap={25}>
- <TodoList todos={todos} />
- </Stack>
- </Stack>
- </div>
- );
- }
-
- 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.
- import React, { useState } from 'react';
- import { Stack,TextField, PrimaryButton } from "@fluentui/react";
-
- function AddTodo(props:any) {
- const [todoName, setTodoName] = useState("");
- const addTodo = () => {
- props.addTodo(todoName);
- setTodoName("");
- }
- const setTodo = (e: any) =>{
- setTodoName(e.target.value);
- }
-
- return (
- <Stack>
- <Stack horizontal >
- <Stack.Item grow>
- <TextField placeholder="Add new item" value={todoName} onChange={setTodo }/>
- </Stack.Item>
- <PrimaryButton onClick={addTodo} >Add</PrimaryButton>
- </Stack>
- </Stack>
- );
- }
-
- 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.
- import React, { useState } from 'react';
- import './App.css';
- import { Stack } from "@fluentui/react";
- import TodoList from './components/TodoList';
- import AddTodo from './components/AddTodo';
-
- function App() {
- const [todos, setTodos] = useState([{ id: 1, name: "Todo Item 1" }, { id: 2, name: "Todo Item 2" }]);
-
- const addTodo = (todoName: string) => {
- if (todoName != "") {
- const newId = todos.length + 1;
- const newTodos = [...todos, { id: newId, name: todoName }];
- setTodos(newTodos);
- }
- };
-
- return (
- <div className="wrapper">
- <Stack horizontalAlign="center">
- <h1>Todo App using Fluent UI & React</h1>
- <Stack style={{ width: 300 }} gap={25}>
- <AddTodo addTodo={addTodo} />
- <TodoList todos={todos} />
- </Stack>
- </Stack>
- </div>
- );
- }
-
- export default App;
Final step is to delete the todo in the list. So first add deleteTodo function in the App component as below,
- const deleteTodo = (id: number) => {
- const newTasks = todos.filter((todo) => { return todo.id !== id });
- setTodos(newTasks);
- };
and pass this function to TodoList component,
- <div className="wrapper">
- <Stack horizontalAlign="center">
- <h1>Todo App using Fluent UI & React</h1>
- <Stack style={{ width: 300 }} gap={25}>
- <AddTodo addTodo={addTodo} />
- <TodoList todos={todos} deleteTodo={deleteTodo} />
- </Stack>
- </Stack>
- </div>
Again from TodoList component pass this deleteTodo function TodoItem component,
- <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,
- import React, { useState } from 'react';
- import { Stack, Label, IconButton, Dialog, DialogFooter, DefaultButton, PrimaryButton, DialogType } from '@fluentui/react';
-
- function TodoItem(props: any) {
- const [openDeleteModal, setOpenModal] = useState(true);
-
- const deleteTodo = (id: number) => {
- props.deleteTodo(id);
- setOpenModal(true);
- }
-
- return (
- <Stack>
- <Stack horizontal verticalAlign="center" horizontalAlign="space-between">
- <Label>{props.todo.name}</Label>
- <IconButton iconProps={{ iconName: 'trash' }} className="clearButton" onClick={() => { setOpenModal(!openDeleteModal) }} />
- </Stack>
- <Dialog
- hidden={openDeleteModal}
- dialogContentProps={{
- type: DialogType.normal,
- title: "Delete",
- subText:
- "Are you sure you want to delete this item? This cannot be undone."
- }}
- modalProps={{
- isBlocking: false
- }}
- >
- <DialogFooter>
- <PrimaryButton text="Yes" onClick={() => { deleteTodo(props.todo.id) }} />
- <DefaultButton text="No" onClick={() => { setOpenModal(true) }} />
- </DialogFooter>
- </Dialog>
- </Stack>
- );
- }
-
- 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.
- import React from 'react';
- import ReactDOM from 'react-dom';
- import './index.css';
- import App from './App';
- import * as serviceWorker from './serviceWorker';
- import { Fabric, initializeIcons } from "@fluentui/react";
-
- initializeIcons();
-
- ReactDOM.render(
- <React.StrictMode>
- <Fabric>
- <App />
- </Fabric>
- </React.StrictMode>,
- document.getElementById('root')
- );
-
- 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.
Happy Coding!!