Essentials

2. Build the UI

In this guide we will be adding static components to our Todo app and we’ll run it in the browser to verify everything works as expected.

Code to follow this guide can be found on Github­ or StackBlitz­.

These files will go in a new src/components folder.

In this Header.tsx component we display a title for the app and below it a text input to create a new task.

import {FC} from "react";

export const Header: FC = () => {
  return (
    <header className="header">
      <h1>BAQ Todos</h1>
      <form>
        <input
          name="task"
          type="text"
          className="new-todo"
          placeholder="What needs to be done?"
          autoFocus
        />
      </form>
    </header>
  );
};

Pressing “enter” is how the new task gets created, so we handle onSubmit on the form to extract the input value and reset it for the next task.

-import {FC} from "react";
+import {FC, FormEvent} from "react";

export const Header: FC = () => {
+  const onSubmit = (e: FormEvent<HTMLFormElement>) => {
+    e.preventDefault();
+
+    // Read the form data and reset it.
+    const form = e.currentTarget;
+    const formData = new FormData(form);
+    form.reset();
+
+    // Read the task title.
+    const newTaskTitle = formData.get("task")?.toString();
+    if (!newTaskTitle) {
+      return;
+    }
+
+    console.log("Got task:", newTaskTitle);
+  };

  return (
    <header className="header">
      <h1>BAQ Todos</h1>
-      <form>
+      <form onSubmit={onSubmit}>
      ...

In this Task.tsx component we display a single task with two possible interactions: a checkbox to mark it as completed and a button to delete it.

import {FC} from "react";

interface TaskProps {
  title: string;
  completed: boolean;
}

export const Task: FC<TaskProps> = props => {
  const {title, completed} = props;

  const onCompletedChange = () => console.log("Completed!");
  const onDeleteClick = () => console.log("Deleted!");

  return (
    <li className={completed ? "completed" : undefined}>
      <div className="view">
        <input
          type="checkbox"
          className="toggle"
          checked={completed}
          onChange={onCompletedChange}
        />
        <label>{title}</label>
        <button className="destroy" onClick={onDeleteClick} />
      </div>
    </li>
  );
};

In this TaskList.tsx component we display a list of tasks with the <Task> component we just created. For now we provide static titles to preview what it’ll look like.

import {FC} from "react";
import {Task} from "./Task";

export const TaskList: FC = () => {
  return (
    <main className="main">
      <ul className="todo-list">
        <Task title="Setup the project" completed={true} />
        <Task title="Build the UI" completed={false} />
      </ul>
    </main>
  );
};

Finally, we update the App.tsx component to add our newly created <Header> and <TaskList> components.

import {FC} from "react";
+import {Header} from "./components/Header";
+import {TaskList} from "./components/TaskList";

export const App: FC = () => {
-  return null;
+  return (
+    <section className="todoapp">
+      <Header />
+      <TaskList />
+    </section>
+  );
};

Start the dev server if it’s not running already:

npm run dev

Navigating to http://localhost:5173/ should display the following:

The static app UI.

We’re now done building our app UI.

© 2024 Quentez