Tracking changes on inputs and textareas in React
Tags: react, input, html
Published: 2024-02-17 12:05:11

This post will cover how to track changes from an input field or text area. You can either follow along and write the code following the steps I will explain or just access the project on Stackblitz using the link I've provided and skip to the explanation.

[Stackblitz project](https://stackblitz.com/~/github.com/Paulvitalis200/Notes-app-react) 

**1. Writing the code**
We'll begin by creating a react app using vite

`npm create vite@latest`

Install all dependencies using:
`npm install`

Now in **App.tsx**, replace all the code with the following block of code

```
import { useState } from "react";
import "./App.css";

interface Note {
  id: number;
  text: string;
  backgroundColor: string;
  date: string;
}

function App() {
  const getRandomColor = (): string => {
    return "hsl(" + Math.random() * 360 + ", 100%, 75%)";
  };

  const [notes, setNotes] = useState<Note[]>([]);

  const [note, setNote] = useState<string>("");

  const [showModal, setShowModal] = useState<boolean>(false);
  const [showError, setShowError] = useState<boolean>(false);
  const addNote = () => {
    if (note.trim().length < 10) {
      setShowError(true);
      return;
    }

    setNotes([
      ...notes,
      {
        id: Math.random(),
        text: note.trim(),
        date: new Date().toLocaleDateString(),
        backgroundColor: getRandomColor(),
      },
    ]);

    toggleModal();
  };

  const handleChange = (event: any) => {
    setNote(event.target.value);
  };

  const resetForm = () => {
    setNote("");
    setShowError(false);
  };

  const toggleModal = () => {
    resetForm();
    setShowModal(!showModal);
  };

  return (
    <>
      {showModal && (
        <div className="modal">
          <div className="modal-content">
            <textarea
              className="text"
              onChange={handleChange}
              value={note}
            ></textarea>
            {showError && (
              <p className="error">Minimum characters allowed is 10</p>
            )}
            <div className="buttons">
              <button className="add-btn" onClick={addNote}>
                Add Note
              </button>
              <button className="close-btn" onClick={toggleModal}>
                Close
              </button>
            </div>
          </div>
        </div>
      )}

      <main>
        <div className="header">
          <h2 className="header-title">Notes</h2>
          <button className="add-note-btn" onClick={toggleModal}>
            +
          </button>
        </div>
        <div className="notes-container">
          {notes.map((note) => {
            return (
              <div
                key={note.id}
                className="note"
                style={{ backgroundColor: note.backgroundColor }}
              >
                <p className="note-text">{note.text}</p>
                <p className="note-date">{note.date}</p>
              </div>
            );
          })}
        </div>
      </main>
    </>
  );
}

export default App;

```


Update the **App.css** to be as follows

```
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.add-note-btn {
  border: None;
  background-color: black;
  color: white;
  border-radius: 50%;
  padding: 10px 13px;
}

.add-note-btn:hover {
  cursor: pointer;
  box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
}


main {
  width: 80%;
  margin: 0 auto;
}

.notes-container {
  display: flex;
  flex-wrap: wrap;
}

.note {
  width: 200px;
  height: 200px;
  border-radius: 10px;
  margin-right: 15px;
  margin-bottom: 20px;
  padding: 10px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.note-text {
  height: 80%;
  overflow: scroll;
  -ms-overflow-style: none;  /* IE and Edge */
  scrollbar-width: none;  /* Firefox */
  word-wrap: break-word;
}

/* Hide scrollbar for Chrome, Safari and Opera */.note-text::-webkit-scrollbar {
  display: none;
}

.modal {
  position: fixed; /* Stay in place */
  z-index: 1; /* Sit on top */
  left: 0;
  top: 0;
  width: 100%; /* Full width */
  height: 100%; /* Full height */
  overflow: auto; /* Enable scroll if needed */
  background-color: rgb(0,0,0); /* Fallback color */
  background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}

/* Modal Content/Box */
.modal-content {
  background-color: #fefefe;
  margin: 15% auto; /* 15% from the top and centered */
  padding: 20px;
  border: 1px solid #888;
  width: 40%; /* Could be more or less, depending on screen size */
  border-radius: 10px;
}

/* The Close Button */
.close {
  color: #aaa;
  float: right;
  font-size: 28px;
  font-weight: bold;
}

.close:hover,
.close:focus {
  color: black;
  text-decoration: none;
  cursor: pointer;
}

.buttons {
  display: flex;
  flex-direction: column;
}

.buttons button {
  margin-top: 8px;
  color: #fff;
  border: none;
  padding: 5px 0;
  font-size: 18px;
  border-radius: 4px;
}

.buttons button:hover {
  cursor: pointer;
}

textarea {
  width: 100%;
  min-height: 100px;
  font-size: 18px;
}

.add-btn {
  background-color: purple;
}

.close-btn {
  background-color: rgb(133, 34, 34);
}

.error {
  color: red;
}

@media only screen and (max-width: 500px) {
  .modal-content {
    width: 80%; /* Could be more or less, depending on screen size */
    
  }
}
```

Finally, Update the **index.css** file too

```
:root {
  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
  /* line-height: 1.5; */
  font-weight: 400;

  color-scheme: light dark;
  color: rgba(255, 255, 255, 0.87);
  background-color: #242424;

  font-synthesis: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a:hover {
  color: #535bf2;
}

body {
  margin: 0;
  place-items: center;
  min-width: 320px;
  min-height: 100vh;
}


@media (prefers-color-scheme: light) {
  :root {
    color: #213547;
    background-color: #ffffff;
  }
  a:hover {
    color: #747bff;
  }
  button {
    background-color: #f9f9f9;
  }
}

```

Save all the changes and run your app with the following command:

`npm run dev`


Your application should now look as follows:

![Initial application view](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fsxhnjwk536yqj5t6ku5.png)

Our application is a notes app that allows us to add notes.

On clicking the **+** icon, we get a modal as follows:


![Modal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v5uurojka53xahgsuy0d.png)

**2. Explanation.**

The textarea field has an initial value set to the **note **variable that we created:

```
<textarea
              className="text"
              onChange={handleChange}
              value={note}
            ></textarea>
```

JavaScript allows us to listen to an input’s change in value by providing the attribute ** onchange**. React’s version of the onchange event handler is the same but camel-cased.

The handleChange function used on the onChange event handler was defined as follows:

```
 const handleChange = (event: any) => {
    console.log(event.target.value)
    setNote(event.target.value);
    console.log("Note: ", note)
  };

```

You can check the console and see the value that is logged out and also the value of the note as you type.


![Console output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aju6if0ioli3gz5kc9ez.png)

The handleChange function simply sets the note variable to be whatever text the user inputs as they type.

And that's it. On change is a very useful event handler and will simplify your work relating to user input on your React journey.

For the source code, you can access it at this link: [Source code](https://github.com/Paulvitalis200/Notes-app-react)

Follow me on:
LinkedIn: [Paul Otieno](https://stackblitz.com/~/github.com/Paulvitalis200/Notes-app-react)
Twitter: [me_huchoma](https://twitter.com/me_huchoma)
Instagram: [paul_dreamer_](https://www.instagram.com/paul_dreamer_)

_Happy Coding!_ 🥂