Search code examples
javascripttypescriptvue.jsvuejs3vuetifyjs3

Vuetify 3 wrapper component props


So I'm looking at wrapping some Vuetify components into my own custom component so I can more finely control the look and feel throughout our application. The issue that I'm running into is that I want to have 'default' props for the Vuetify component, and that works fine, BUT when I also add props when consuming the component, these are 'override' props are not being used.

Vue 3.2.38, Vuetify 3.1.10

Custom Component:

<template>
  <label v-if="name">{{ name }}</label>
  <v-text-field v-bind="{ ...$attrs, ...$props, ...defaultProps }">
    <template v-for="(_, scopedSlotName) in $slots" #[scopedSlotName]="slotData">
      <slot :name="scopedSlotName" v-bind="slotData" />
    </template>
    <template v-for="(_, slotName) in $slots" #[slotName]>
      <slot :name="slotName" />
    </template>
  </v-text-field>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import { VTextField } from 'vuetify/components/VTextField';

export default defineComponent({
  name: 'EmailField',
  extends: VTextField,
  props: {
    name: {
      type: String,
      default: ''
    }
  },
  computed: {
    defaultProps() {
      return {
        color: 'yellow',
        bgColor: '#252836',
        variant: 'outlined',
        density: 'compact'
      };
    }
  }
});
</script>

Consuming the component:

<template>
  .......other template items

  <EQEmailField v-model="email" name="Email Address" counter :persistentCounter="true"  color="blue" density="comfortable" />
  
</template>

<script lang="ts">
import { defineComponent, defineAsyncComponent } from 'vue';

export default defineComponent({
  components: {
    EmailField: defineAsyncComponent(() => import('@/components/custom/email-text-field.vue'))
  }
});
</script>

So the default props(defaultProps) that I set in the component work fine and apply to Vuetify correctly. The issues arise when consuming the component and I pass props to override the default components props. They default props are always used and the passed in props on the consumer side are not being used. If I try to override a value that's in my defaultProps object then it doesn't work. If I use a prop that I don't already have set in defaultProps then it works fine. So I'm guessing I need a way to parse through the props and determine which one to actually apply? I realize this may be a tough thing to do but seems like this would be a somewhat common occurrence.


Solution

  • Just define them as props with default values that you've listed in computed proeprty :

    export default defineComponent({
      name: 'EmailField',
      extends: VTextField,
      props: {
        name: {
          type: String,
          default: ''
        },
        color:{
          type:String,
          default:'yellow'
        },
       //the same process for other props
      },
        
    });
    

    then in template :

      <v-text-field v-bind="{ ...$attrs, ...$props}">