How to extend the prop typings of a native HTML element in Vue?

Viewed 706

Lets say I have an element that wraps an input and takes all of its properties, in addition to a few more.

In react this would be typed as

interface ExtendedInputProps extends React.ComponentPropsWithoutRef<'input'> {
    some: Type
}

And it's a pretty common use case. I'm aware that Vue 3 generates its prop types based on whatever is passed to the props: object in defineComponent.

I'm imaging doing something like:

props:{
    ...getComponentProps('input')
    additionalProp: String
}

But I have no idea how to do that and can't find any docs on it. Is it possible?

1 Answers

Simplest case is when input is the root element of the component, then you don't need to declare anything extra, just pass attributes to your component and they will be passed down

//NumberInput Component
<template>
    <input :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"  />
</template>

<script setup lang="ts">
defineEmits(["update:modelValue"])
const props = withDefaults(defineProps<{
    modelValue?: number
}>(), { modelValue: 0 })
</script>

It can be used this way:

<number-input v-model="data" type="text" placeholder="123-45-678" />

where type and placeholder will end up as input element's attributes.

If you have input nested inside your component, you need to disable attribute inheritance:

//NumberInput Component
<template>
  <div class="wrapper">
    <input :value="modelValue" v-bind="$attrs" 
      @input="$emit('update:modelValue', $event.target.value)"  />
  </div>

</template>

<script setup lang="ts">
defineEmits(["update:modelValue"])
const props = withDefaults(defineProps<{
    modelValue?: number
}>(), { modelValue: 0 })
</script>

<script lang="ts">
// normal `<script>`, executed in module scope (only once)
// declare additional options
export default {
  inheritAttrs: false,
  customOptions: {}
}
</script>

Note that we have added second script tag to disable inheritAttrs and added v-bind="$attrs" to input to pass attributues down explicitly. More on the topic you can find out here

Related