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

Using v-model on a custom Element (from defineCustomElement): prop/event mismatch #4428

Closed
sawden opened this issue Aug 24, 2021 · 8 comments
Assignees
Labels
has PR A pull request has already been submitted to solve the issue scope: custom elements scope: v-model ✨ feature request New feature or request

Comments

@sawden
Copy link

sawden commented Aug 24, 2021

Version

3.2.4

Reproduction link

CodeSandbox Link

Steps to reproduce

Create a custom input as a CustomElement and use it in a Vue component.

What is expected?

The value specified in the v-model changes

What is actually happening?

v-model is ignored.

@LinusBorg
Copy link
Member

Strictly speaking this is not really a bug as the custom element does what it's supposed to do: it emits the component event as a custom event. The problem is that v-model listens for input but the custom element emits an update:modelValue event.

However we should discuss how we can better support this common usecase.

@LinusBorg LinusBorg changed the title customElements v-model BUG Using v-model on a custom Element (from defineCustomElement): prop/event mismatch Aug 24, 2021
@LinusBorg
Copy link
Member

LinusBorg commented Aug 24, 2021

On second thought, I'm inclined to rate this as a bug. There's a few different aspects to this, the thing to discuss is wethe we want to support v-model on a custom element at all. We currently support it on distinct native input elements only (and components, but we are dealing with a custom DOM element here).

If we decided to do this, we would have to make the v-model listener deal with custom events, where the emitted value is found in a detail property. This would complicate things quite a bit.

But regardless of that discussion, the thing that makes it a bug right now, though, is that there's no way to actually listen to the update:modelValue event though - because we explicitly skip these special events on DOM elements (because they get special treatment on native inputs).

https://github.com/vuejs/vue-next/blob/b40845153cd4dbdd76bfb74816f4e6b109c9f049/packages/runtime-dom/src/patchProp.ts#L30-L32

So even if the consumer doesn't use v-model and tries the following, they will fail:

<custom-element :model-value="value" @update:model-value="value = $event.detail"

...because the event listener is never being applied to the custom element. Which is desirable for normal DOM elements, of course, but poses an issue here.

I'll think a bit about it and write more thoughts later

@sawden
Copy link
Author

sawden commented Aug 24, 2021

The styles of child vue component are not applied if the parent component is a custom element. #4309
Because of this, I have to define my custom input as a custom element, otherwise I cannot use any styles.

I thank you for your help and hope that a solution/workaround will be found soon. 🙂

✌ue is awesome!

@LinusBorg LinusBorg self-assigned this Aug 25, 2021
@mathieumagalhaes
Copy link

I didn't want to create another issue for it, as this seems related:

v-model does not work on <component :is="..."> components either.
Reproduction: https://codesandbox.io/s/customelement-v-model-bug-forked-w4p21s?file=/src/App.vue

For <component is="input"> one could use @input="value = $event.target.value"
But I would have rather used v-model which worked in Vue 2

Bumped into this as my use case for this was single component for both textarea and input.

@haoqunjiang haoqunjiang added the has PR A pull request has already been submitted to solve the issue label Aug 31, 2023
@padcom
Copy link

padcom commented Nov 24, 2023

@LinusBorg Did you think about it? It's November 2023 and this is still an issue. It's also a regression from Vue 2.x (https://www.digitalocean.com/community/tutorials/how-to-add-v-model-support-to-custom-vue-js-components) and is blocking me personally from achieving my goal of creating custom elements that do support v-model (like a custom for example).

@jcbond92
Copy link

jcbond92 commented Dec 20, 2023

I have a PR up that addresses this issue (at least partially) for custom elements.

It allows you to specify a v-model type for different custom elements (like checkbox, radio, etc.). Library authors will need to mirror native input props (e.g. value, checked) and input/change events (while also mirroring changes to value/checked on the host element so that updated values are in event.target), but it'll be possible to make v-model form bindings work across different types of custom elements.

@yyx990803
Copy link
Member

First of all, a general opinion: Vue custom elements are first and foremost custom elements, so they should strive to behave like native DOM elements where applicable. It is discouraged to author Vue custom elements that only work in Vue applications.

With that in mind, a Vue custom input element should behave like a native <input> element as much as possible - i.e. expose a value property, and emit input events. This makes it possible to both work with v-model when used inside a Vue app, and also be usable when it's used in a non-Vue environment.

When v-model is used on a custom element, Vue should treat it the same way whether the custom element is a Vue one or not. So it will listen for the update event and attempts to read the .value property.

Therefore, to make a Vue custom element work with v-model, it should:

  1. Declare a value prop
  2. When the value changes, (1) update the .value property on the host element and (2) emit an input event.

Before 3.5, retrieving the host element can be a bit difficult. That's why 3.5 will ship with a new useHost() helper and expose this.$host for Options API.

Here's a working example using the minor branch (to be published as 3.5).

@jcbond92
Copy link

jcbond92 commented Aug 9, 2024

Thanks for adding useHost() that will make updating the host element much easier. With regard to using radio and checkbox custom elements with v-model, is the recommendation to use type="checkbox" or type="radio" to have Vue apply the correct type of v-model?

I'd be happy to raise a PR to mention this in the Vue docs, if so!


There is a bit more detail in this feature discussion around why I think this would be a helpful thing to document or have an official solution for, vuejs/rfcs#617:

Setting app.config.compilerOptions.isCustomElement works well for text input components where I can emit an input event and use a value prop, but I am unable to support checkboxes and radio buttons since V_MODEL_DYNAMIC is looking for event.target.value instead of event.target.checked.

The workaround here is to set a type on the host element like this:

<template>
  <custom-checkbox type="checkbox" v-model="value">Label</custom-checkbox>
</template>

<script>
import "@custom-element-package/checkbox.js"
export default {
  data() {
    return {
      value: true
    };
  },
};
</script>

@github-actions github-actions bot locked and limited conversation to collaborators Aug 24, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
has PR A pull request has already been submitted to solve the issue scope: custom elements scope: v-model ✨ feature request New feature or request
Projects
None yet
7 participants