Skip to content

CustomEvent options in Vue web components #745

Open
@krubengineer

Description

Creating an issue out of this ⬇ hoping for more discussion!

Discussed in #433

Originally posted by athewsey February 25, 2022
I recently came across vuejs/vue#12433 because I have a use case for this feature too - and saw that the original requester was asked to bring it here to the RFCs process but couldn't find any such issue/PR/discussion yet.

Essentially, I'm using Vue to build some Custom Elements / native web components which emit events. As noted in the 'Events' section of the Vue Web Components doc:

Events emitted via this.$emit or setup emit are dispatched as native CustomEvents on the custom element. Additional event arguments (payload) will be exposed as an array on the CustomEvent object as its details property.

The challenge here is that, because params are fed directly through to options.detail on the CustomEvent constructor, I don't see any way to set other Event options - particularly bubbles and cancelable.

These are important features for native/DOM event handling, and it seems to me like it's not sufficient to just assume one setting always holds because presumably developers using this feature are doing so because (like me) their architecture is not vanilla "Vue-all-the-way-down".

It seems possible to work around my specific bubbling requirement by manually raising a CustomEvent and setting composed true, to allow it to bubble out of the shadow root and up through parents:

<!-- MyCoolComponent.ce.vue -->
<script setup lang="ts">
import { ref } from "vue"

const props = defineProps<{ val: number }>();
const thisEl = ref<HTMLElement>();
const emit = defineEmits<{
  (e: "foobar", val: number): void;
}>();

function onClickRemove() {
  // No way to set bubbling via this VueJS option:
  // emit("foobar", props.val);

  // Can set bubbling via native, but extra complexity:
  thisEl.value.dispatchEvent(
    new CustomEvent(
      "foobar",
      {
        detail: [props.val],
        bubbles: true,
        composed: true,
      }
    )
  );
}
</script>

<template>
  <p @click="onClick();">Click me</p>
</template>

...But I don't see how it can be done today without the composed option (which I guess could be a problem for users with multiple nested shadow roots in their page?).

I'm new to Vue's codebase and RFC process, but hopefully we can find a way to support this extra configuration that's still consistent-enough with what users are familiar with in normal Vue $emit?

Activity

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

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions