vuejs / core

đź–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
45.58k stars 7.99k forks source link

Custom elements not able to associate with form #10948

Open Reaper88 opened 1 month ago

Reaper88 commented 1 month ago

Vue version

3.4.27

Link to minimal reproduction

https://stackblitz.com/edit/vitejs-vite-ikoo1s?file=src%2Fcomponents%2Fui%2Ftime-picker%2FTimePicker.ce.vue

Steps to reproduce

Choose time and submit form

What is expected?

To have the custom element as a form-associated custom element

What is actually happening?

The element is not taken as part of the form when submitted

System Info

System:
    OS: Linux 4.18 Rocky Linux 8.9 (Green Obsidian)
    CPU: (8) x64 Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz
    Memory: 12.06 GB / 23.02 GB
    Container: Yes
    Shell: 4.4.20 - /bin/bash
  Binaries:
    Node: 20.9.0 - ~/.nvm/versions/node/v20.9.0/bin/node
    npm: 10.4.0 - ~/.nvm/versions/node/v20.9.0/bin/npm
    pnpm: 8.15.3 - ~/.local/share/pnpm/pnpm
  Browsers:
    Chrome: 123.0.6312.122

Any additional comments?

I've looked high and low, tried attachInternals() but on the button and a template ref doesn't work either, I'd like to have a way to associate the custom element as a form-associated custom element which we can do in vanilla js. But it's during the creation of the HTMLElement class that you can set it but we cannot modify this with the new defineCustomElement method.

Tjaitil commented 1 month ago

+1. I have also searched high and low for the very same thing you are describing. It seems like a big limitation in defineCustomElement to not being able to pass arguments to the underlying CustomElement constructor. In this case attachInternals & static formAssociated properties.

Did you find any solution to your problem?

Sidenote: Here is an older issue (see latest comment) I found, which also adresses some of the same problems.

https://github.com/vuejs/rfcs/issues/220

Reaper88 commented 1 month ago

The only way to bypass this is to set a hidden input with the right name and value thru js but it kinda defeats the purpose of creating a custom element in my opinion.

lejunyang commented 1 week ago

I think we could have a formAssociated option in defineCustomElement, and add that static prop in VueCustomElement

static formAssociated = !!Comp.formAssociated

ElementInternals should be attached if we want to make it associate with form. ElementInternals can also be used to access Accessibility Object Model and Custom Element State. So we should call attachInternals if supported (Or add another option?)

constructor(initialProps?: Record<string, any>) {
  super(Comp, initialProps, hydrate);
  if (this.attachInternals) this._internals = this.attachInternals();
}

Then, users can utilize _internals if they want But not sure if we should just add formAssociated as a common component option(for .vue file), I am using this solution for defineCustomElement in tsx only. If that's ok, I can make a PR for this.

For temp solution, check out this, I made some changes based on your demo

Tjaitil commented 2 days ago

I came to the same alternative approach as you @lejunyang. But in my opinion that kind of defeats the purpose of using vue with web components with such a custom solution.

If this is something that won't implement then I think there is an argument that this should be reflected in the docs; https://vuejs.org/guide/extras/web-components. As of today the docs makes it sound "plug and play" when working with web components and vue. Which is to some degree true, but there are lacking functionality.