Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trouble controlling checkbox #3486

Closed
1 task
danyo1399 opened this issue Mar 21, 2022 · 7 comments
Closed
1 task

Trouble controlling checkbox #3486

danyo1399 opened this issue Mar 21, 2022 · 7 comments

Comments

@danyo1399
Copy link

danyo1399 commented Mar 21, 2022

  • Check if updating to the latest Preact version resolves the issue

Describe the bug
I cannot get a controlled checkbox to work in preact

To Reproduce
See simple example
https://codesandbox.io/s/preact-controlled-checkbox-w1fn9g

Steps to reproduce the behavior:

  1. click checkbox (should be checks)
  2. Click again and (should stay checked

Expected behavior
the checkbox should be controlled by state
React example of the same controlled checkbox
https://codesandbox.io/s/react-controlled-checkbox-lebx4j

@developit
Copy link
Member

As @JoviDeCroock's tag implies, this is fixed in the next major release of Preact.

In the meantime, there are actually two separate things happening here: one is that Preact 10 doesn't quite cover all controlled components cases, and the other is an oddity in the way checkboxes work in the DOM.

The latter DOM issue is an interesting one. The behavior here can be recreated identically with or without Preact:

let checkbox = document.createElement('input');
checkbox.type = 'checkbox';
document.body.appendChild(checkbox);

checkbox.onclick = e => {
  checkbox.checked = true;
  e.preventDefault();
};

(here's that code running on JSFiddle: https://jsfiddle.net/developit/bdx8kmwu/)

There are two workarounds for this: one is to avoid calling preventDefault on click events generated by a checkbox. In Preact 10, that will cause the component to become uncontrolled, so it's not useful until that fix rolls out. The other solution is to defer the assignment of checkbox.checked = true so that it happens after the "click" event is over. Here's an updated vanilla DOM example that does just that:

checkbox.onclick = e => {
+ setTimeout(() => {
    checkbox.checked = true;
+ });
  e.preventDefault();
};

(notice how this fixes the issue when working directly with the DOM: https://jsfiddle.net/developit/3a9eysxh/)

It's not an ideal solution, for sure, but it does work. In Preact, you can simply wrap the state setter in a setTimeout:

function click(ev) {
-   setState(true);
+   setTimeout(() => setState(true));
    ev.preventDefault()
}

@danyo1399
Copy link
Author

Thank you for the response. I forgot to mention that I worked around the issue with set timeout in my ticket.

Appreciate all the work being done

@JoviDeCroock
Copy link
Member

I will close this ticket as it's present in v11 and we have a workaround provided, thank you so much for taking the time to reproduce and everything!

@rgalanakis
Copy link

Sorry to resurrect this, but since this is fixed in 11, and still present in the latest release of 10, and 11 doesn't have a firm release (as per #2621), I'm wondering if the fix could be backported?

I see https://preactjs.com/guide/v10/forms#checkboxes--radio-buttons too, which maybe means this is no longer considered a 'fix', and we should use controlled inputs only? But it was very confusing that this code resulted in an uncontrolled input in Preact, whether or not controlled inputs are suggested as a way forward (which will personally take me a long time to wrap my head, and our codebase, around, coming from React).

        <div>
          <input type="checkbox" id={"my special id"} name={"some name"} checked={true} />
          <label htmlFor={"my special id"}>
            hi
          </label>
        </div>

@rschristian
Copy link
Member

I'm wondering if the fix could be backported?

Unlikely; there's been a few attempts but none have worked out.

and we should use controlled inputs only?

Controlled inputs aren't really a thing in Preact, so you can't only use them.

Refs, as we mention at the top of the forms doc, is the way to go about controlling inputs if you need to.

@rgalanakis
Copy link

Controlled inputs aren't really a thing in Preact, so you can't only use them.

Sorry, I meant uncontrolled as per that docs page and PR discussion. I was surprised this was the recommendation because so far Preact is working fine with all our controlled inputs with react-bootstrap 😅

Thanks for the update!

@rschristian
Copy link
Member

so far Preact is working fine with all our controlled inputs with react-bootstrap

More likely they don't really make use of being controlled, which is actually pretty common.

But yeah, generally better to use uncontrolled when possible, the DOM is perfectly capable of handling state in most cases. When you need tighter control, refs are there, but no need to jump to using them until needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants