The Kirk Concept, We unlock brand dominance through branding, design systems, and app development.

onClick event fires the input twice.

Sat May 22 2021Written by: Christopher Jones

onClick event listener is firing my functino twice, but WHY?!

onClick event fires the input twice

This week was a great week development wise but I came across an extremely interesting bug that I could not solve for the life of me. I will break down the scenario shortly but just know the solve for it is way too simple.

The Problem

I needed to create a custom checkbox input component that hides the input to allow for a custom element to be displayed instead of the radio. Now accesibility rules say that you should always wrap your input's with a label so I did as so.

<label htmlFor='option1' onClick={() => setValueOfInput(!valueOfInput)}>
    <input type='checkbox' id='option1' className='hidden-input' />
    {children}
</label>

My goal was to toggle the value of the input onClick to mimic the same experience of a normal checkbox. When I ran my dev server I realized onClick the setValueOfInput function was firing twice and setting the value from false to true back to false.

Things I Tried

My first thing to check were where all of my setter functions were being called and it was only on the label itself so it didn't make sense to me that it fired twice. I also checked the onClick event that it had a callback to wait for the event, in case it was firing on render and then firing again on click. And then of course I checked all of my useEffects to ensure nothing was forcing the onClick to fire on every change, all clear.

SO WHAT IN THE WORLD IS SETTING MY VARIABLE

The solution

After 2 hours of banging my head up against my monitor, I checked my code again and realized the onClick event listener was being applied to the label. Which the label itself doesn't have a value or "selected" value tied to it, so it looks for the input element that matches its "for" property and applies any event listeners to that input. So the onClick event with the function setValueOfInput was firing on the label because the label had the event listener and then it was firing again on the input which fired the same exact function again!

So the corrected code looks like this:

<label htmlFor='option1'>
    <input
        // Moved the onClick handler to the input!
        onClick={() => setValueOfInput(!valueOfInput)}
        type='checkbox'
        id='option1'
        className='hidden-input'
    />
    {children}
</label>

The reason this works is because the htmlFor property and the id it is tied to which binds them as the same element. If the label is now clicked it will fire the onClick of the input ONCE! Problem Solved.

Last Words

I really hope this article saves you 2 hours of migrains and computer damage lol. This is something simple that I have learned the hard way for sure but this is how you learn right! Let me know if you experienced this or something similar.

👍🏾 Thanks for reading.

ready for brand dominance?

We love working with businesses that have been validated and are serious about making a statement in their industry! If you are interested in any of our services and want to see how we can work together, fill out our questionnaire and let's get started!