0

I would like to create a checkbox with basic checkbox functionality (ie. you click it, the checkbox is selected, you click it again, it is unchecked).

However, this action is not happening (the checkbox remains checked regardless of whether I click it or not).

Here is my code:

export const check: checkComponent = ({ id, checked = false, disabled, onChange }) => {
  ...
  return (
      ...
      <label
        className={classNames("inputCheckboxLabel", {
          "inputCheckboxLabel--checked": checked,
          "inputCheckboxLabel--disabled": disabled,
        })}
      />
      <input
        id={inputId}
        type="checkbox"
        className="inputCheckboxLabel--input"
        checked={checked}
        disabled={disabled}
        onChange={() => onChange(!checked)}
      />
    </div>
  )
}

Here is my css:

.inputCheckboxLabel--input {
  display: none;
}
.inputCheckboxLabel {
  border: 1px solid var(--color-light-shade);
  background-color: var(--color-lighter-shade);
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 0.125rem;
  width: 1.25rem;
  height: 1.25rem;
  cursor: pointer;
}
.inputCheckboxLabel--checked:before {
  content: " ";
  width: 100%;
  height: 100%;
  border-color: var(--color-constructive);
  background-color: var(--color-constructive);
}
.inputCheckboxLabel--disabled {
  cursor: progress;
}

Here is how the checked prop is getting passed down:

  const [approved, setApproved] = useState(transaction.approved)
  ...
      <InputCheckbox
        id={transaction.id}
        checked={approved}
        disabled={loading}
        onChange={async (newValue) => {
          await consumerSetTransactionApproval({
            transactionId: transaction.id,
            newValue,
          })

          setApproved(newValue)
        }}
      />
Emm
  • 2,367
  • 3
  • 24
  • 50
  • what is the `checked` prop you are passing in to the `checkComponent`? Unless it's equal to the `approved` state variable, it won't be altered by the `onChange` and therefore won't change on click. (Also even if it is, it will only update with a delay if `consumerSetTransactionApproval` takes an appreciable time - you should probably call this *after* calling `setApproved`, or not `await` it at all because the `setApproved` call isn't dependent on anything it does, at least as far as we can see.) – Robin Zigmond Mar 10 '23 at 23:11
  • @RobinZigmond The `checked` prop is equal to the `approved` state variable. I updated my question to show how the `checked` prop is getting passed down – Emm Mar 10 '23 at 23:15
  • thanks, this doesn't look like it will produce the problem you describe then. Unless something else in the parent component is calling `setApproved`? It would help to see a live demo of your non-working code, either in a Stack Overflow snippet here in your question (you can include React in those), or on an external site like CodeSandbox. – Robin Zigmond Mar 10 '23 at 23:22
  • your onChange listener should be `e => onChange(e.target.value)`. I'm not sure if this will fix it but it's a start. – naffetS Mar 10 '23 at 23:28
  • Actually, see this: https://stackoverflow.com/questions/26615779/react-checkbox-not-sending-onchange You need to switch to `defaultChecked` due to the way checkboxes work in React. – naffetS Mar 10 '23 at 23:32
  • 1
    @naffetS it would be `e.target.checked` (rather than `value`) for a checkbox. But although unusual, and not what I would recommend, what the OP has done here ought to work - the `onChange` ignores the whole event argument entirely and just sets the `checked` property to the opposite of what it was. The only obvious way this might fail is if something else is overriding that `checked` property, hence the suggestion in my last comment. – Robin Zigmond Mar 10 '23 at 23:44
  • @RobinZigmond Yeah, that was a typo. If you read the question I linked (which I think this is a duplicate of), apparently `checked` won't work in this case - using `defaultChecked` is what needs to be used. Apparnetly you can also use `checked` but use `onClick` instead of `onChange`. – naffetS Mar 10 '23 at 23:54
  • I've never had a problem making a controlled checkbox with React using `event.target.checked`. `defaultChecked` is completely different and should only be used for uncontrolled checkboxes, to set the initial state (see [React docs](https://reactjs.org/docs/dom-elements.html#checked)). I didn't look in detail at the question you link to but that's talking about a more complex situation involving refs (and most of the answers look like nonsense to me at first glance - using `onClick` instead of `onChange`??) – Robin Zigmond Mar 11 '23 at 12:51
  • `async` event handler is always a bad idea. Maybe it's because `setApproved(newValue)` is only called after `consumerSetTransactionApproval()` has finished ? So maybe `checked` will be set, but later that you expect ? Or `consumerSetTransactionApproval()` never resolves, ans `setApproved` never called ? – kca Mar 11 '23 at 23:07

0 Answers0