In the simplest scenario, if the input serves as the root element of the component, there is no need to declare any additional settings. You can simply pass attributes to your component and they will automatically cascade 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>
Usage example:
<number-input v-model="data" type="text" placeholder="123-45-678" />
In this case, the type
and placeholder
attributes will be directly applied to the input element.
If the input is nested within the component, attribute inheritance needs to be disabled:
//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>
It's important to note that a second script tag has been added to turn off inheritAttrs
and include v-bind="$attrs"
for explicit attribute passing. For further details on this topic, refer to this resource.