Forem

Cover image for Tracking changes on inputs and textareas in React
Paul Vitalis
Paul Vitalis

Posted on

1

Tracking changes on inputs and textareas in React

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

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;



Enter fullscreen mode Exit fullscreen mode

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 */

  }
}


Enter fullscreen mode Exit fullscreen mode

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;
  }
}



Enter fullscreen mode Exit fullscreen mode

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

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

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

Modal

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>


Enter fullscreen mode Exit fullscreen mode

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)
  };



Enter fullscreen mode Exit fullscreen mode

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

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

Follow me on:
LinkedIn: Paul Otieno
Twitter: me_huchoma
Instagram: paul_dreamer_

Happy Coding! 🥂

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more

👋 Kindness is contagious

Immerse yourself in a wealth of knowledge with this piece, supported by the inclusive DEV Community—every developer, no matter where they are in their journey, is invited to contribute to our collective wisdom.

A simple “thank you” goes a long way—express your gratitude below in the comments!

Gathering insights enriches our journey on DEV and fortifies our community ties. Did you find this article valuable? Taking a moment to thank the author can have a significant impact.

Okay