Search code examples
javascripttypescriptvue.jsvuejs3web-component

How to build a Vue web component which reflects an internal state as an attribute?


I am building a web component input which looks like this with Vue 3:

<my-input value="Search"></my-input>

How can I make sure that the value attribute is always equivalent to the current internal value?


Solution

  • Vue 3 is not really made with web components in mind. All Vue-internal APIs like defineModel(), defineExpose() or defineEmits() will not be properly translated when using defineCustomElement().

    You can however solve this with custom logic:

    <script setup lang="ts">
    import { ref, watch, computed } from 'vue';
    
    const props = defineProps<{
      value?: string;
    }>();
    
    const $search = ref();
    const instance = computed(() => ($input.value?.getRootNode() as ShadowRoot)?.host);
    
    const query = ref(props.value ?? '');
    watch(query, () => instance.value.setAttribute('value', query.value));
    </script>
    
    <template>
      <input v-model.trim="query" ref="$input">
    </template>