Build a To-Do App with Node.js, Express, and Vanilla JavaScript

Computer Science

Build a To-Do App with Node.js, Express, and Vanilla JavaScript

JavaScriptNode.jsExpress

Build a To-Do App with Node.js, Express, and Vanilla JavaScript

Turn your current HTML and early React experience into a small full-stack to-do app. You will keep the interface simple, add a Node.js and Express server, connect browser JavaScript to server routes, and finish with a runnable project that lets someone add, view, complete, and remove tasks.

5 modules19 lessonsComputer ScienceJavaScriptNode.jsExpressHTMLCSSFetch APInpm

What you learn by building this

  • Create and run a small Node.js project with Express
  • Serve an existing-style HTML, CSS, and JavaScript front end from an Express server
  • Design and implement task routes using JSON request and response data
  • Use vanilla JavaScript and fetch to read and update server data
  • Represent task state consistently across the server and browser
  • Handle invalid input and visible success or error feedback

Learning Journey

1

Shape the interface and task behavior

4 lessons

Start from the learner's demonstrated HTML and CSS foundation. Build a standalone browser version first so the project has a visible interface and predictable task behavior before introducing the server runtime.

2

Introduce the Express server

3 lessons

Cross the runtime bridge in small steps: create the Node project, run one server, then serve the already-working front end. The learner sees the same project working through Express before learning API design.

3

Move task data behind the API

4 lessons

Replace the browser-only task array with a deliberately small in-memory server model. Each step adds one route and immediately gives the browser a more realistic source of truth.

4

Connect the browser to the server

4 lessons

Use the learner's working browser interactions as the bridge into asynchronous programming. Replace local mutations one at a time with fetch calls, preserving the interface while changing its data source.

5

Polish, verify, and present the project

4 lessons

Turn the working prototype into a reliable portfolio-sized project. The learner checks the important paths, improves the interface details, and prepares a concise demonstration of the finished app.

Public lesson

Plan the task screen

Lesson 3.1 — Give the task screen a clear structure

You already know how to organize a semantic HTML page. This time, you’ll apply that same thinking inside a React component. For now, the screen only needs to look like a to-do page; behavior comes later.

1. See what the app currently renders

Tasks

Start the React app using the command your project already uses, such as:

npm run dev

Open the local URL in your browser.

Tasks

Look at the current screen and identify where the main app component is defined. It is often one of these:

  • src/App.jsx
  • src/App.js
  • src/App.tsx

Keep the existing imports and component setup. You’ll replace the component’s returned markup.

2. Sketch the page before writing JSX

Your page needs these regions:

  1. A page heading
  2. A form for adding a task
  3. A region containing the current tasks
  4. Controls for each task
  5. A feedback area for messages such as “Task added”

Use semantic elements so the page structure is understandable even without styling:

  • <main> for the page’s primary content
  • <header> for the title and short introduction
  • <section> for the form and task list
  • <form> for entering a task
  • <ul> and <li> for the tasks
  • <label> connected to the text input
  • <button> for actions

Tasks

Before coding, decide what each section should be called. For example, the form section could be “Add a task” and the list section could be “Your tasks.”

3. Build the JSX structure

Replace only the returned markup in your main component. The comments below are places where your page-specific JSX is still needed.

<!-- tangeble:starter -->
function App() {
  return (
    <main className="todo-page">
      {/* Add a header with the page title and a short description. */}

      <section aria-labelledby="add-task-heading">
        {/* Add an h2 whose id matches aria-labelledby. */}

        <form>
          {/* Add a label connected to the task text input. */}
          {/* Add a text input with a useful name and placeholder. */}
          {/* Add a submit button. */}
        </form>
      </section>

      <section aria-labelledby="task-list-heading">
        {/* Add an h2 whose id matches aria-labelledby. */}

        <ul>
          {/* Add two sample li elements so the page is visibly populated. */}
          {/* Each task should have a checkbox, task text, and delete button. */}
        </ul>
      </section>

      {/* Add a feedback paragraph with an accessible live-region role. */}
    </main>
  );
}

export default App;

A few JSX details matter here:

  • Use className, not class.
  • Use htmlFor on a <label>, and make it match the input’s id.
  • Give the form input a name.
  • Give each button a clear type, such as submit or button.
  • A checkbox should have a label or text that makes its purpose clear.

Tasks

Do not add state or event handlers yet. Static sample tasks are enough for this lesson.

4. Add just enough styling to read the structure

Use the stylesheet already connected to your app. If it is src/App.css, add styles that make the regions and task controls easy to distinguish.

<!-- tangeble:starter -->
.todo-page {
  /* Set a readable width and spacing for the page. */
}

.todo-page header {
  /* Add spacing below the page introduction. */
}

.todo-page section {
  /* Add separation between the form and task list regions. */
}

.todo-page ul {
  /* Remove the default list indentation and add vertical spacing. */
}

.todo-page li {
  /* Arrange the checkbox, text, and delete button clearly. */
}

.feedback {
  /* Make feedback easy to notice without overpowering the tasks. */
}

Tasks

Choose simple values that fit the rest of the project. The goal is not visual polish; it should be immediately obvious where the form, list, controls, and feedback are.

5. Check the result in the browser

Tasks

Refresh the page and verify all of the following:

  • The page has one clear main heading.
  • The form has a visible label, text input, and submit button.
  • The task list has at least two visible tasks.
  • Each task has a checkbox and a delete button.
  • The form and task list have their own visible headings.
  • A feedback message appears somewhere on the page, even if it is currently static.
  • The layout remains understandable when the browser window is narrow.

Tasks

Then use the keyboard:

  1. Press Tab repeatedly.
  2. Confirm that the input, submit button, checkboxes, and delete buttons receive focus.
  3. Check that the focus order follows the page from top to bottom.
  4. Press the spacebar on a checkbox and confirm that it can be toggled.

Find the bug

Something's wrong — can you spot it?

If a label does not focus its input when clicked, compare the label’s htmlFor value with the input’s id. They must match exactly.

6. Make one structural review

Explain it back

Put it in your own words

Open your component and ask:

  • Could someone understand this page from the headings alone?
  • Is the task collection represented as a list rather than unrelated paragraphs?
  • Does every action use a button?
  • Is the feedback area separate from the task content?
  • Did any element receive a class only because it was convenient, when a semantic element would be clearer?

20 more characters

When the browser shows a clearly organized task page and keyboard navigation reaches every control, this screen structure is ready for the next lesson.

Course Outline

5 modules · 19 lessons

Shape the interface and task behavior

Introduce the Express server

Move task data behind the API

Connect the browser to the server

Polish, verify, and present the project

Learn by building your own version.

Remix this public project to open the workspace, follow the guided build, and let the AI mentor teach you through the work instead of doing it for you.