Challenge of Managing Multiple Inputs in a React Component

Having trouble with a React component that involves splitting a 9-digit code across three input fields. The issue arises when I enter more than 3 digits in one field, as it doesn't shift to the next field as expected. Also, pasting a 9-digit code into the first field leaves the others blank. Any help would be greatly appreciated!

Exploring solutions for my React component.

export default function VoucherPage() {
  const router = useRouter();
  const [secret, setSecret] = useState<string>("");
  const [inputs, setInputs] = useState<SecretCode>({
    input1: "",
    input2: "",
    input3: "",
  });

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setInputs((prevState) => ({
      ...prevState,
      [e.target.name]: e.target.value,
    }));
  };

  return (
    <div className="top_page_container">
      <div className={styles.voucher_container}>
        <input
          maxLength={3}
          className={styles.voucher_input}
          name="input1"
          onChange={handleInputChange}
          value={inputs.input1}
        ></input>
        <input
          maxLength={3}
          className={styles.voucher_input}
          name="input2"
          onChange={handleInputChange}
          value={inputs.input2}
        ></input>
        <input
          maxLength={3}
          className={styles.voucher_input}
          name="input3"
          onChange={handleInputChange}
          value={inputs.input3}
        ></input>
      </div>
      <Button
        style={{
          width: "16em",
        }}
        onClick={handleSubmit}
      >
        Submit
      </Button>
    </div>
  );
}

Customizing my CSS

.voucher_input {
  width: 6ch;
  font-size: 1.3rem;
  padding: 0 1rem;
  border-radius: 0.24em;
  padding: 0.2em;
  text-align: center;
}
.modal_container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1em;
}

Answer №1

To achieve the desired behavior, it's crucial to incorporate additional logic into your handleInputChange function. Take note of the following steps:

1. Update the input field based on user input. 2. When the value in the field reaches its maxLength, shift focus to the next input field. 3. If the user pastes a string, divide it into sections of 3 digits each and update all input fields accordingly.

Below is an illustration of how you can implement these adjustments.

export default function VoucherPage() {
  const router = useRouter();
  const [secret, setSecret] = useState<string>("");
  const [inputs, setInputs] = useState<SecretCode>({
    input1: "",
    input2: "",
    input3: "",
  });

  const inputRefs = useRef([React.createRef(), React.createRef(), React.createRef()]);

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>, inputIndex: number) => {
    let inputValue = e.target.value;

    // Check for paste action
    if(inputValue.length > 3) {
      let parts = inputValue.match(/.{1,3}/g); // split string into parts of length 3
      setInputs({
        input1: parts[0] || '',
        input2: parts[1] || '',
        input3: parts[2] || '',
      });
    } else {
      setInputs(prevState => ({...prevState, [e.target.name]: inputValue}));

      if(inputValue.length === 3 && inputIndex < 2) {
        // Focus on the next input field
        inputRefs.current[inputIndex + 1].current.focus();
      }
    }
  };

  return (
    <div className="top_page_container">
      <div className={styles.voucher_container}>
        <input
          ref={inputRefs.current[0]}
          maxLength={3}
          className={styles.voucher_input}
          name="input1"
          onChange={(e) => handleInputChange(e, 0)}
          value={inputs.input1}
        ></input>
        <input
          ref={inputRefs.current[1]}
          maxLength={3}
          className={styles.voucher_input}
          name="input2"
          onChange={(e) => handleInputChange(e, 1)}
          value={inputs.input2}
        ></input>
        <input
          ref={inputRefs.current[2]}
          maxLength={3}
          className={styles.voucher_input}
          name="input3"
          onChange={(e) => handleInputChange(e, 2)}
          value={inputs.input3}
        ></input>
      </div>
      <Button
        style={{
          width: "16em",
        }}
        onClick={handleSubmit}
      >
        Submit
      </Button>
    </div>
  );
}

In the code snippet above, I introduced an inputRefs array to store references to the three input elements for manual focus setting. Also, the handleInputChange function now includes an inputIndex parameter to determine the next focused input field. Additionally, the index is passed along with the event object in the onChange props of the input elements.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Bootstrap 5 - multiple columns of equal width, except for one that fills the remaining space

Imagine a situation where I am using Bootstrap 5 and have the following code snippet... <div class="container"> <div class="row row-cols-auto"> <div class="col">One</div> <div class="c ...

When it comes to HTML and Javascript drawing, getting the positioning just right can be a challenge

I'm currently developing a control website for a drawing robot as part of a school project. However, I've been facing some challenges with the functionality of the drawing feature. Though I admit that the site lacks attention to detail, my main ...

What is the best way to show static files from the backend in a React application?

Currently, my setup involves a React application connected to an Express-Node.js backend through a proxy. Within the backend, there are some static files in a specific directory. When I make requests and embed the response link in the "src" attribute of an ...

Tips for modifying the value and refreshing the array

I retrieve data from $scope.roleinfo = {"QA":[{"White Box Testing":0},{"Black Box Testing":0}],"Development":[{"Server Side":0},{"UI":0},{"Back end":0}]}; Then, I present these values in a table. Now, I need to update the maxcount and create an array w ...

The dynamic addition of divs to the HTML body is causing them to overlap

Check out this functional plunker that is nearly complete. The current issue I am facing is with the chat divs being dynamically added to the body using $compile, but they all have the same CSS class and end up overlapping each other, like so: .chat-wind ...

Experimenting with enzyme to test React portals

I've run into a challenge while attempting to write tests for a modal component using React fiber's portal. The issue arises because my modal is mounted to a domNode on the root of the <body />, but since that domNode doesn't exist dur ...

Encountered an error stating 'Cannot read property 'user' of undefined' while attempting to generate a user document during account creation using Firebase

I'm having trouble adding the user ID to a new collection named 'accounts' during account creation. I keep encountering an error that says 'Cannot read property 'user' of undefined'. Can someone please help me troubleshoo ...

What is the best approach for extracting the content of mouse hover elements using Python and selenium through a loop?

I am currently working on a project where I am utilizing Selenium to extract information from a mouse hover box that appears to display relevant details for each review. While I was successful in retrieving data for the first review, I am facing challeng ...

Retrieve the total count of tables within a specific div element

If I have an unspecified amount of tables within a div, how can I determine the total number of tables using either plain JavaScript or jQuery? ...

Updating SVG colors using VueJS

I'm struggling to change the color of an existing static SVG image. Here's the code I have: <img class="icon-shop" src="@/assets/icon-shop.svg"/> <style> .icon-shop { width: 32px; fill: orange; stroke: oran ...

Struggling to interact with a field within an HTML/CSS LESS document

I have encountered an issue with my website where I am unable to click on certain fields or buttons within the Login fieldset. Strangely, I can only interact with the fields and buttons located within the Register fieldset. The CSS for my website is writt ...

What are some techniques for obtaining the second duplicate value from a JSON Array in a React JS application by utilizing lodash?

Currently, I am tackling a project that requires me to eliminate duplicate values from a JSON array object in react JS with specific criteria. My initial attempt was to use the _.uniqBy method, but it only retained the first value from each set of duplicat ...

Unable to uncheck all checkboxes

My checkbox list has a checkbox at the top to select all checkboxes, but after selecting them all, I encounter issues in clearing them. Here is the code snippet for the implementation: class App extends React.Component { state = { checked: undefined } ...

Error arises when uploading csv files to Node.js with Multer due to an unexpected field presence

I'm currently working on implementing a file upload feature with the use of Node.js, Vue, and Multer. Below is the Vue.js front-end code: export default { data(){ return{ selected: "How do you want to input the data?", options: [ ...

Designing a dropdown menu with sub-menus that appear when hovered over

In my quest to design CSS that will dynamically display links in left-to-right divs, I am seeking a way for sub-menus to appear below the menu being rolled over. The challenge lies in the fact that these menus will be loaded from a WordPress database, mean ...

Showing the state on a different page: A step-by-step guide

I'm currently in the process of creating a model for a real estate website. On the homepage, users can choose between 'rent' or 'purchase' using a select option and view the results on that page. I have successfully stored the sear ...

Guide on adding an image to a Bootstrap card component

I'm facing a simple issue that I can't seem to solve. As a beginner in using bootstrap, I'm struggling to figure out how to insert an image into the card header. I've been searching online for solutions for the past 30 minutes with no l ...

Using a ternary operator in a Text component within React Native

Is it possible to create a ternary condition where if {title} contains the text "appl" then the style 'styles.label' will change to 'styles.label_2'? const Field = ({ title, info }: Props) => { return ( <View style={styles.c ...

Is it possible to generate two types of helper text in Material-UI React?

I am a beginner in the world of MUI and React, but I'm taking on some small tasks to ease the workload of our busy developers. One task I'm tackling is adding descriptive helper text to a few fields retroactively. Currently, we have error helper ...

Is this considered a table?

In the realm of web development, there is a well-known mantra: "Only use tables for tabular data." This advice stems from a time when tables were misused for all sorts of layout purposes. While I generally adhere to this guideline, there are moments when ...