Build a Next.js Interactive Web-Based To-Do List App

Written by

in

Tired of scattered sticky notes and endless mental lists? In today’s fast-paced world, staying organized is key to productivity. A well-structured to-do list app can be a game-changer, helping you manage tasks, track progress, and ultimately, achieve your goals. This tutorial will guide you, step-by-step, through building your own interactive to-do list application using Next.js, a powerful React framework for building modern web applications. We’ll explore core concepts, write clean and efficient code, and equip you with the knowledge to create a fully functional and user-friendly to-do list app.

Why Build a To-Do List App with Next.js?

Next.js offers several advantages that make it an excellent choice for this project:

  • Server-Side Rendering (SSR) & Static Site Generation (SSG): Next.js can render your app on the server or generate static HTML at build time, leading to improved SEO and faster initial page loads. This is crucial for user experience and search engine visibility.
  • React-Based: If you’re familiar with React, Next.js will feel like a natural extension. It leverages the power of React for building user interfaces.
  • Routing: Next.js simplifies routing with its file-system-based routing, making it easy to create different pages and navigate between them.
  • API Routes: Next.js allows you to create API endpoints directly within your project, simplifying backend integration.
  • Optimized Performance: Next.js automatically optimizes images, code splitting, and more, resulting in a performant application.

Building a to-do list app with Next.js provides a practical learning experience, allowing you to master fundamental web development concepts while creating something useful.

Prerequisites

Before we begin, ensure you have the following installed:

  • Node.js and npm (or yarn): You’ll need Node.js and npm (Node Package Manager) or yarn to manage project dependencies. You can download them from https://nodejs.org/.
  • A Code Editor: Choose a code editor like Visual Studio Code, Sublime Text, or Atom.
  • Basic Knowledge of HTML, CSS, and JavaScript: Familiarity with these languages is essential for understanding the code.
  • A little React experience: Next.js uses React, so a basic understanding will be helpful.

Setting Up Your Next.js Project

Let’s get started by creating a new Next.js project. Open your terminal and run the following command:

npx create-next-app todo-app

This command will create a new directory named “todo-app” with all the necessary files and configurations for your Next.js project. Navigate into the project directory:

cd todo-app

Now, start the development server:

npm run dev

Open your browser and go to http://localhost:3000. You should see the default Next.js welcome page. This confirms that your project is set up correctly.

Project Structure

Let’s briefly examine the basic project structure:

  • pages/: This directory contains your application’s pages. Each file in this directory becomes a route. For example, `pages/index.js` becomes the route `/`.
  • public/: This directory is for static assets like images, fonts, and other files.
  • styles/: This directory contains your CSS or styling files.
  • package.json: This file lists your project’s dependencies and scripts.

Creating the To-Do List Components

We’ll create two main components:

  • TodoItem: Represents a single to-do item.
  • TodoList: Manages the list of to-do items.

Creating the TodoItem Component

Create a new file named `components/TodoItem.js` (you’ll need to create a `components` folder in the root directory). Add the following code:

import React from 'react';

function TodoItem({ todo, onToggle, onDelete }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', padding: '10px', borderBottom: '1px solid #ccc' }}>
      <input
        type="checkbox"
        checked={todo.completed}
        onChange={() => onToggle(todo.id)}
        style={{ marginRight: '10px' }}
      />
      <span style={{ textDecoration: todo.completed ? 'line-through' : 'none', flexGrow: 1 }}>
        {todo.text}
      </span>
      <button onClick={() => onDelete(todo.id)} style={{ marginLeft: '10px', padding: '5px 10px', backgroundColor: '#f00', color: '#fff', border: 'none', borderRadius: '4px', cursor: 'pointer' }}>Delete</button>
    </div>
  );
}

export default TodoItem;

This component displays a single to-do item with a checkbox for marking it as complete, the text of the to-do item, and a delete button. It receives `todo`, `onToggle`, and `onDelete` as props. The `onToggle` function updates the completion status of the to-do item, and `onDelete` removes the item.

Creating the TodoList Component

Create a new file named `components/TodoList.js`. This component will manage the list of to-do items and handle adding new items. Add the following code:

import React, { useState } from 'react';
import TodoItem from './TodoItem';

function TodoList() {
  const [todos, setTodos] = useState([]);
  const [newTodo, setNewTodo] = useState('');

  const addTodo = () => {
    if (newTodo.trim() !== '') {
      setTodos([...todos, { id: Date.now(), text: newTodo.trim(), completed: false }]);
      setNewTodo('');
    }
  };

  const toggleTodo = (id) => {
    setTodos(
      todos.map((todo) =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  };

  const deleteTodo = (id) => {
    setTodos(todos.filter((todo) => todo.id !== id));
  };

  return (
    <div style={{ maxWidth: '600px', margin: '20px auto', padding: '20px', border: '1px solid #ccc', borderRadius: '8px' }}>
      <h2 style={{ textAlign: 'center' }}>My To-Do List</h2>
      <div style={{ display: 'flex', marginBottom: '10px' }}>
        <input
          type="text"
          value={newTodo}
          onChange={(e) => setNewTodo(e.target.value)}
          placeholder="Add a new task"
          style={{ padding: '8px', marginRight: '10px', flexGrow: 1, borderRadius: '4px', border: '1px solid #ccc' }}
        />
        <button onClick={addTodo} style={{ padding: '8px 15px', backgroundColor: '#007bff', color: '#fff', border: 'none', borderRadius: '4px', cursor: 'pointer' }}>Add</button>
      </div>
      <div>
        {todos.map((todo) => (
          <TodoItem key={todo.id} todo={todo} onToggle={toggleTodo} onDelete={deleteTodo} />
        ))}
      </div>
    </div>
  );
}

export default TodoList;

This component manages the state of the to-do items using the `useState` hook. It handles adding new tasks, toggling the completion status, and deleting tasks. It also renders the `TodoItem` components for each to-do item.

Integrating the Components into the Main Page

Now, let’s integrate these components into our main page (`pages/index.js`). Replace the content of `pages/index.js` with the following code:

import TodoList from '../components/TodoList';
import Head from 'next/head';

export default function Home() {
  return (
    <div style={{ fontFamily: 'sans-serif' }}>
      <Head>
        <title>My To-Do List</title>
        <meta name="description" content="A simple to-do list app built with Next.js" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <TodoList />
    </div>
  );
}

This imports the `TodoList` component and renders it on the page. We’ve also added a “ component to set the page title and meta description. The `Head` component is crucial for SEO.

Adding Basic Styling

While the inline styles in the components work, let’s add some basic styling using CSS Modules. Create a file named `styles/TodoList.module.css` and add the following:

.todoList {
    max-width: 600px;
    margin: 20px auto;
    padding: 20px;
    border: 1px solid #ccc;
    border-radius: 8px;
}

.inputContainer {
    display: flex;
    margin-bottom: 10px;
}

.input {
    padding: 8px;
    margin-right: 10px;
    flex-grow: 1;
    border-radius: 4px;
    border: 1px solid #ccc;
}

.addButton {
    padding: 8px 15px;
    background-color: #007bff;
    color: #fff;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}

Now, import this CSS module into your `TodoList.js` file:

import styles from '../styles/TodoList.module.css';

And apply the styles to the corresponding elements:


<div className={styles.todoList}>
  <div className={styles.inputContainer}>
    <input
      type="text"
      value={newTodo}
      onChange={(e) => setNewTodo(e.target.value)}
      placeholder="Add a new task"
      className={styles.input}
    />
    <button onClick={addTodo} className={styles.addButton}>Add</button>
  </div>
  <div>
    {todos.map((todo) => (
      <TodoItem key={todo.id} todo={todo} onToggle={toggleTodo} onDelete={deleteTodo} />
    ))}
  </div>
</div>

CSS Modules help you avoid naming conflicts and make your styles more maintainable. They scope your CSS classes to the component, preventing styles from unintentionally affecting other parts of your application.

Testing Your Application

At this point, you should have a functional to-do list app. Open your browser and navigate to http://localhost:3000. You should be able to:

  • Add new to-do items.
  • Mark items as complete.
  • Delete items.

Make sure all the functionalities are working as expected. If you encounter any issues, double-check your code, especially for typos or missing imports.

Common Mistakes and How to Fix Them

Here are some common mistakes and how to fix them:

  • Incorrect Import Paths: Double-check your import paths to ensure they point to the correct files. This is a very common issue.
  • Missing State Updates: Make sure you’re correctly updating the state using `setTodos` and `setNewTodo`. Incorrect state updates won’t reflect the changes in the UI.
  • Typographical Errors: Typos in your code can cause unexpected behavior. Carefully review your code for any errors.
  • Incorrect Event Handlers: Ensure that your event handlers (e.g., `onChange`, `onClick`) are correctly wired up to the corresponding functions.
  • CSS Module Issues: If your CSS styles aren’t being applied, ensure you’ve imported the CSS module correctly and are using the class names with the correct syntax (e.g., `className={styles.className}`). Also, check for any CSS conflicts.

Enhancements and Next Steps

This is a basic to-do list app. You can enhance it further with the following features:

  • Local Storage: Save the to-do items to local storage so they persist across browser sessions. This is a very important feature.
  • Filtering: Add filters to show all, active, or completed tasks.
  • Editing: Allow users to edit the text of existing to-do items.
  • Drag and Drop: Implement drag-and-drop functionality to reorder the tasks.
  • User Authentication: Implement user authentication to allow multiple users to manage their to-do lists.
  • Backend Integration: Connect to a backend database to store the data more persistently.
  • Styling: Improve the styling using a CSS framework like Tailwind CSS, Bootstrap, or Material UI.
  • Responsive Design: Make the app responsive to different screen sizes.

SEO Best Practices

To ensure your app ranks well on search engines, follow these SEO best practices:

  • Descriptive Title and Meta Description: Use a clear and concise title and meta description in the “ component. This helps search engines understand the content of your page.
  • Semantic HTML: Use semantic HTML elements (e.g., `<h1>`, `<h2>`, `<p>`, `<nav>`, `<article>`) to structure your content. This helps search engines understand the hierarchy of your content.
  • Keyword Optimization: Naturally incorporate relevant keywords (e.g., “to-do list”, “Next.js”, “task management”) in your content, title, and meta description. Avoid keyword stuffing.
  • Image Optimization: Optimize images for size and use descriptive alt text.
  • Mobile-Friendly Design: Ensure your app is responsive and works well on mobile devices.
  • Fast Loading Speed: Optimize your code and images to ensure your app loads quickly. Next.js helps with this by default.
  • Create Sitemap: Generate a sitemap to help search engines crawl and index your site.
  • Use Heading Tags: Use heading tags (H2, H3, etc.) to structure your content and improve readability.

Summary / Key Takeaways

In this tutorial, we built a functional to-do list app using Next.js. We covered the core concepts of Next.js, created reusable components, managed state, and implemented basic styling. You learned how to set up a Next.js project, create components, handle user input, and display data. The key takeaway is that Next.js makes it easy to build modern, performant web applications with a focus on SEO and user experience. By following these steps, you’ve gained a solid foundation for building more complex and feature-rich web applications with Next.js.

FAQ

  1. Can I use a different CSS framework?

    Yes, you can use any CSS framework like Tailwind CSS, Bootstrap, or Material UI. You’ll need to install the framework and import its CSS files into your project.

  2. How do I deploy this app?

    You can deploy your Next.js app to platforms like Vercel (which is recommended, as it’s built by the Next.js team), Netlify, or AWS. You’ll typically need to build your app using `npm run build` before deploying.

  3. How can I add persistence (saving tasks)?

    You can use local storage to save tasks in the browser, or integrate a backend to save to a database. For local storage, use `localStorage.setItem` and `localStorage.getItem`. For a backend, you’d create API routes in Next.js to interact with the database.

  4. How do I handle errors?

    You can add error handling using `try…catch` blocks in your functions. For example, when fetching data from an API, wrap the fetch call in a `try…catch` block to handle potential errors.

Building a to-do list app is a great starting point for learning Next.js and web development in general. The concepts you’ve learned here can be applied to a wide range of web projects. Keep exploring, experimenting, and building! As you delve deeper into Next.js, you’ll discover its full potential for creating amazing user experiences. Remember, the best way to learn is by doing, so keep coding and building, and don’t be afraid to experiment with new features and techniques. Your journey into the world of web development has just begun.