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

Input checkbox value won't change when trigger is coming from click #13083

Closed
michalkolek opened this issue Mar 21, 2025 · 2 comments
Closed

Comments

@michalkolek
Copy link

michalkolek commented Mar 21, 2025

Vue version

3.5.13

Link to minimal reproduction

https://play.vuejs.org/#eNp9Uk1v2zAM/SuELnGAwEaR7ZLa2UfXQ3fYim1HAYNi045bWRIk2ctg+L+Xkus0BYqeJD4+ko9PGtkXY9KhR7ZjuSttazw49L3Zc9V2RlsPI1isN1DqzvQeK5igtrqDFRWtuCq1ch4EFIGVcCY4W18vcN1a538a32pFhKVDkqyh2INIByF7hKIoYCVWL1XCe+xIRwEJRubIFQCmxuKAyn/DWvTSJ+trwpzX5t5qIxoRphAYuOfWr4ZEcfCJzgOduzkm/sRVns2709YUhPFSeKQIID9e7W+OWD4e9AldnlEYYVKzH0cxTXkWrhGT4oAyXiloFW0LuzLUYlVwduEGzf9cyrZ8JPh5XYL8f4MExAqaxtlzqztwR93LCg4I5VGohl6BHI0N4txsGZxnF9rZhnlHltZtkz44reiJo5M0gV6ilWhnMY6z3exxyAkp9b/vEfO2x82CR1Vv4A+OhAYz7y06tANyds55YRukzUL69vcPPNH9nOx01Utiv5P8hU7LfjYs0L72qiLZF7yo9i5+1FY1f9ztyaNyy1JBaGBOkc8Zfdmbd1Z/kbtNP8Q6+hzk4t8BbehJBm7Tj+nVlk1PF4wOOQ==

Steps to reproduce

  1. Create a Vue component with the following code:
<script setup>
import { ref, computed } from 'vue'
const a = ref("a");
const firstOption = computed(() => a.value === 'a');
const attempt = (e) => {
  e.preventDefault(); e.stopPropagation();
  a.value = a.value === "a" ? "b" : "a";
}
</script>

<template>
  <h1>Checkboxes</h1>
  <pre>{{a}}</pre>
  <label>
    <input :checked="firstOption" @click="attempt" type="checkbox">
    I should be changed on click
  </label>
</template>
  1. Load the component in your application
  2. Observe the initial state of the checkbox
  3. Click the checkbox
  4. Notice that while the value of a toggles between "a" and "b" (visible in the pre tag), the checkbox state does not change properly

What is expected?

The checkbox should toggle between checked and unchecked states when clicked.

What is actually happening?

The value of a changes (as shown in the

 element), but the checkbox state doesn't reflect this change correctly.

System Info

Reproducible in vue sfc playground

Any additional comments?

@michalkolek michalkolek changed the title Input checkbox value won't change Input checkbox value won't change when trigger is coming from click Mar 21, 2025
@dariasavinova
Copy link

Hi! This is expected behaviour because preventDefault() blocks the checkbox’s native state change.
Vue binds :checked, which only reflects state but doesn't control it after the initial render.
Since the browser manages checkbox toggling, preventing the default action stops it from updating.

To fix this in your code, either remove preventDefault() or use v-model instead of :checked.

@edison1105 edison1105 closed this as not planned Won't fix, can't repro, duplicate, stale Mar 22, 2025
@skirtles-code
Copy link
Contributor

Just to expand on this a little...

Vue binds :checked, which only reflects state but doesn't control it after the initial render.

I don't think this is entirely accurate. Under normal circumstances Vue would update a bound checked value after the initial render. e.g. See this example:

Clicking the button in that example does update the rendered checked state of the checkbox.

The problem in the reproduction seems to be very specific: you can't update the checked property in a click handler that has called preventDefault(). I've created a JSFiddle to demonstrate this same problem in vanilla JS/HTML:

This seems quite unintuitive to me, preventing the default action somehow cancels manually overriding the checked value.

I found a related discussion on Stack Overflow:

Based on that discussion, what seems to be happening is:

  • When the user clicks, the browser immediately updates the value of checked based on the click.
  • The browser then runs the click handler.
  • preventDefault() is called in the handler. This just sets an internal flag, it doesn't immediately change the value of checked.
  • Vue updates the value of checked.
  • Once the event has finished propagating, the browser checks the internal flag for 'prevent default'. Given the flag is set, it then resets the value of checked to its old value.

I've put together another example to try to illustrate this:

In particular, notice the logged value of 3. checked. That's logged after Vue updates the value of checked, and it does appear to be in sync with the underlying state. But that gets lost when the browser resets the checked value after propagation.

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

No branches or pull requests

4 participants