Issue with React Component: Radio Button Background Does Not Change on Initial Click

Currently, I am developing a React form where my goal is to dynamically change the background color of a label when a radio button is selected. However, upon clicking or checking the button, it seems that the state needs to be updated first before displaying the desired background color.

To handle this functionality, I am utilizing a combination of onChange and checked attributes to maintain the state of the radio buttons.

In my quest for answers, I even consulted Chat-GPT, but unfortunately, it didn't provide me with the correct solution.

Below you will find the code snippet for the Task component along with its associated CSS styling:

import React, { useState } from 'react';

export default function Task() {
  let [formData, setformData] = useState({
    uName: '', 
    uGender: '', 
    uMedals: 0, 
  });

  let handleForm = (e) => {
    let { name, value } = e.target;

    e.preventDefault();

    if (name === 'uMedals') {
      value = parseInt(value);

      if (value <= 0)
          value = 0;

      if (value > 20) 
          value = formData.uMedals;
    }

    setformData((formData) => ({
      ...formData,
      [name]: value,
    }));
  };

  return (
    <div className='parent-container'>
      <div className='content-wrapper'>
        <div className='left'>
          <form className='form-wrapper'>
            <div className='name-wrapper'>
              <label>Name</label>
              {/* Name input */}
            </div>
            <div className='toogle-wrapper'>
              <label className='lbl-gen'>Gender</label>
              <div className='wrapper'>
                <div className='custom-input'>
                  <input
                    type='radio'
                    id='female'
                    name='uGender'
                    value='female'
                    onChange={handleForm}
                    checked={formData.uGender === 'female'}
                  />
                  <label htmlFor='female'>Female</label>
                </div>
                <div className='custom-input'>
                  <input
                    type='radio'
                    id='male'
                    name='uGender'
                    value='male'
                    onChange={handleForm}
                    checked={formData.uGender === 'male'}
                  />
                  <label htmlFor='male'>Male</label>
                </div>
              </div>
            </div>
            <button style={{ width: '320px' }}>Add</button>
          </form>
        </div>
      </div>
    </div>
  );
}

Here is the corresponding CSS code for the above Task component:

.custom-input input[type=radio] {
    display: none;
}
.custom-input label {
    display: block;
    padding: 6px 8px;
    color: #fff;
    font-weight: bold;
    text-align: center;
    transition: all 0.4s ease;
    cursor: pointer;
    border-radius: 4px;
    background-color: #717762;
}
.custom-input input[type='radio']:checked + label {
    background-color: #f5f5f5; 
    color: #000;
}

Answer №1

To change the background color on the first click, you should remove e.preventDefault() from the handleForm function.

function Task() {
  const [formData, setformData] = React.useState({
    uName: "",
    uGender: "",
    uMedals: 0,
  });

  const handleForm = (e) => {
    let { name, value } = e.target;
    if (name === "uMedals") {
      value = parseInt(value);
      if (value <= 0) value = 0;
      if (value > 20) value = formData.uMedals;
    }
    setformData((formData) => ({
      ...formData,
      [name]: value,
    }));
  };

  return (
    <div className="parent-container">
      <div className="content-wrapper">
        <div className="left">
          <form className="form-wrapper">
            <div className="name-wrapper">
              <label>Name</label>
              {/* Name input */}
            </div>
            <div className="toogle-wrapper">
              <label className="lbl-gen">Gender</label>
              <div className="wrapper">
                <div className="custom-input">
                  <input
                    type="radio"
                    id="female"
                    name="uGender"
                    value="female"
                    onChange={handleForm}
                    checked={formData.uGender === "female"}
                  />
                  <label htmlFor="female">Female</label>
                </div>
                <div className="custom-input">
                  <input
                    type="radio"
                    id="male"
                    name="uGender"
                    value="male"
                    onChange={handleForm}
                    checked={formData.uGender === "male"}
                  />
                  <label htmlFor="male">Male</label>
                </div>
              </div>
            </div>
            <button style={{ width: "320px" }}>Add</button>
          </form>
        </div>
      </div>
    </div>
  );
}

ReactDOM.render(<Task />, document.getElementById("root"));
.custom-input input[type=radio] {
    display: none;
}
.custom-input label {
    display: block;
    padding: 6px 8px;
    color: #fff;
    font-weight: bold;
    text-align: center;
    transition: all 0.4s ease;
    cursor: pointer;
    border-radius: 4px;
    background-color: #717762;
}
.custom-input input[type='radio']:checked + label {
    background-color: #f5f5f5; 
    color: #000;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>

Answer №2

When designing your styles in CSS, make sure to utilize the sibling combinator (+) correctly. This selector targets the element that directly follows another specific element. Therefore, it's essential to keep the label right after the input field within the same .custom-input container for the rule to take effect.

Answer №3

You have encountered an issue with conflicting event systems in React and the browser.

Summary: The problem can be solved by removing e.preventDefault() without any negative consequences.

React alters the handling of click events for radio buttons and checkboxes to ensure consistency across different browsers. Using preventDefault on the event prevents the browser from visually updating the input, although it still updates the state.

Updating the state triggers a re-render of the component. Even though the visual update may not happen after the first click due to preventDefault, subsequent clicks will properly reflect the updated state visually.

The discrepancy between the checked attribute and the actual checked state may contribute to the conflict between browser and React event logic. Removing unnecessary preventDefault() calls can resolve this issue.

If you encounter issues while debugging, consider that console logs may only trigger for the initial click event.

This behavior has been observed since at least 2015, with the reasoning behind the React event handling changes dating back to compatibility concerns with older browsers like IE8. As modern browsers improve, there is a likelihood that React's custom event logic may eventually be phased out in favor of standard browser event handling.

In your scenario, removing the call to e.preventDefault() is recommended as it aligns with the desired default behavior of checking the radio button.

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

A guide on retrieving the upload status of a file using an AJAX post request

Is there a way to retrieve the status of uploaded files when the user cancels the process while uploading multiple files using an ajax call? This is how I am currently making the ajax request to upload files: var request = $.ajax({ url: 'file ...

How can unicode (%u2014) be handled in JavaScript or C#/.NET?

While browsing through the vast expanse of the internet (specifically on a review site like Rotten Tomatoes), I stumbled upon %u2014. This particular string reminded me of something I once encountered in JavaScript. Although I can't quite recall if it ...

Is it possible to include a div above a centered image?

Currently I am working with ImageFlow and I would like to overlay a div on top of the image when it is clicked, sliding it into the center. I have been looking through the JavaScript file but the function MoveIT() seems to be called multiple times and I am ...

Using MongoMapper with Rails to efficiently render arrays in views

In my Rails application, I have a controller that retrieves data from MongoDB. The specific field I need is actually an array, and I want to display it in an erb view. Currently, my workaround involves setting the JavaScript variable directly in the view ...

Unfortunately, the http-proxy-middleware seems to be ineffective within a React application

I am facing an issue with a proxy setup for one of my microservices that has authentication APIs const {createProxyMiddleware} = require('http-proxy-middleware') module.exports = function (app) { app.use( '/auth', createProxyMi ...

Issue with React Bootstrap Datepicker not displaying properly

I'm currently exploring how to integrate the Bootstrap datepicker feature into my React project. I followed the guidelines provided in this forum thread: React DatePicker Bootstrap up to date. The import statements in my code are as follows: import F ...

Is there a way to prevent certain folders that have .vue files from being included in the VueJS build process?

https://i.sstatic.net/YU1rB.png module.exports = { presets: [ '@vue/app' ], module:{ rules: [ { test: /\.vue$/, exclude: [ './src/components/Homepages/number1', './src ...

The truncation of the Gantt Highcharts layout

After analyzing the incoming data, I successfully generated a gantt chart. However, I am facing an issue where the last row is not displaying correctly and is getting cut off. Despite spending a significant amount of time examining it, I have been unable t ...

Development of a custom waterfall toolbar design using MUI framework

I've been working with a setup similar to the one found here: https://codesandbox.io/s/1op5mqq9oq By clicking on the checkboxes, the <Toolbar /> is displayed. As you scroll down the page, the <Toolbar /> remains fixed at the top and even ...

Utilize the serialized data to pre-fill the form fields

After using the serialize() function on my form and saving the string, I am now looking for a function that can repopulate values back into the form from the serialized string. Is there such a function available? ...

Tips for utilizing the Apollo cache consistently during page transitions in NextJs

In the official examples repository of NextJS, I found this apolloClient.js file: import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client' import { concatPagination } from '@apollo/client/utilities' import merge from &apos ...

Optimizing React performance for working with massive matrices

My Minesweeper game is built using React-Redux with simple visuals. The game needs to handle very large boards in the form of matrices (up to 400x400). To avoid mutability, I have to re-render the entire matrix whenever a player clicks on a tile. For la ...

Vue.js caution about "Unnecessary non-emits event listeners" alert for events within RouterView

Is there a way for me to trigger events from my child components and have them reach the top-level App.vue component even though I am using a RouterView to render the child components in the App.vue template? <template> <Navbar /> <c ...

Tips for maintaining a deployed static ReactJS site on the Google Cloud Platform

After completing the instructions in this tutorial, I have managed to deploy a ReactJS website. Now, my query is regarding the process of modifying or updating the site with a new build/version. ...

Troubleshooting Incorrect Image Alignment in Pygame: Solutions and Fixes

While trying to position my hovering image next to my mouse pointer, I want it to be exactly on the mouse cursor instead of slightly separated from it. You can see an example in this VIDEO EXAMPLE. Currently, the image is displayed next to the mouse pointe ...

What is the best way to adjust the row height of a DT::datatable in a Shiny app that includes a checkbox column?

After finding this solution, I successfully implemented a column of checkboxes in a datatable using Shiny. However, I encountered an issue where the row heights could not be adjusted with DT::formatStyle() when the checkbox column was present. Below is a s ...

Retrieve data from HTML in order to apply styling to an element

I am attempting to set the width of my .bar-1 outer span element based on the value of my inner span element. <span class="bar bar-1"> <span name="PERCENTAGE" id="PERCENTAGE" disabled="" title="Total Percentage" maxlength="255" value="66" tabinde ...

JavaScript does not display checkbox values

I am currently testing whether checkbox values appear on the client side. When I execute the code, the alert is not showing anything. I would greatly appreciate any assistance, thank you. <div> <label name="finishing"class=" ...

What is the best way to include regular text before a hyperlink on my ascx page?

I would like to include regular text before a hyperlink. I am inserting my hyperlink using the code below How do I insert a "Go To" in front of the Text = "PreRegistration Work Queues"? <td> <asp:HyperLink ID="hyperlink2" ...

Discovering the content within table cells by utilizing JavaScript functions linked to specific IDs

I am currently working on a project that involves a dropdown list: <select id="itemsList" onchange="gettingList()"> <option>Please choose an option</option> <option value="50">Shampoo</option ...