What's up with $attrs in Vue 3

Natalia Tepluhina

Staff Frontend Engineer

Core Team Member

Google Dev Expert

Vue 2 custom component

@N_Tepluhina

<custom-input 
  label="User name"
  type="text"
  class="btn-primary"
  style="color: blue"
  @submit="submitForm"
  v-model="inputText"
></custom-input>

<custom-input> code

@N_Tepluhina

Vue.component('custom-input', {
  template: `
    <input 
      id="my-input"
      :value="value"
      @input="$emit('input', $event.target.value)"/>
  `,
  props: ['label', 'value']
})

Vue 2 - properties

@N_Tepluhina

$attrs = {
  type: 'text'
}
$props = {
  label: 'User name',
  value: 'hello'
}
$listeners = {
  input: function invoker(),
  submit: function invoker()
}

Vue 2 - rendered result

@N_Tepluhina

@N_Tepluhina

 template: `
  <label for="my-input">
    {{ label }}
    <input 
      id="my-input"
      :value="value"
      @input="$emit('input', $event.target.value)"/>
  </label>
 `,

@N_Tepluhina

Vue 2 - v-bind="$attrs"

@N_Tepluhina

inheritAttrs: false,
template: `
  <label for="my-input">
    {{ label }}
    <input
      v-bind="$attrs"
      id="my-input"
      :value="value"
      @input="$emit('input', $event.target.value)"/>
  </label>
`,

Vue 2 v-bind="$attrs"

@N_Tepluhina

Vue 3

@N_Tepluhina

$attrs = {
  class="btn-primary",
  onSubmit: () => {},
  'onUpdate:modelValue': () => {},
  style: {
    color: 'blue'
  },
  type: 'text'
}
$props = {
  label: "User name",
  modelValue: "hello"
}

@N_Tepluhina

app.component('custom-input', {
  inheritAttrs: false,
  template: `
    <label for="my-input">
      {{ label }}
      <input
        v-bind="$attrs"
        id="my-input"
        :value="modelValue"
        @input="$emit('update:modelValue', $event.target.value)"/>
    </label>
  `,
  props: ['label', 'modelValue'],
})

Vue 3 v-bind="$attrs"

Vue 3 v-bind="$attrs"

@N_Tepluhina

Vue 3 - how to save class?

@N_Tepluhina

app.component('custom-input', {
  inheritAttrs: false,
   computed: {
    filteredAttrs() {
      const newAttrs = {...this.$attrs};
      delete newAttrs.class;
      return newAttrs;
    }
  },
  template: `
    <label for="my-input" :class="$attrs.class">
      {{ label }}
      <input
        v-bind="filteredAttrs"
        id="my-input"
        :value="modelValue"
        @input="$emit('update:modelValue', $event.target.value)"/>
    </label>
  `,
})

Vue 3 fragments

@N_Tepluhina

template: `
<div>Hello!</div>
<label for="my-input">
  {{ label }}
  <input
    id="my-input"
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"/>
</label>
`

Vue 3 fragments

@N_Tepluhina

Always use v-bind="$attrs" with multi-root component

@N_Tepluhina

Vue 3 emits property

@N_Tepluhina

app.component('custom-input', {
  inheritAttrs: false,
  emits: ['submit'],
  template: `
    ...
  `
}
$attrs = {
  class="btn-primary",
  'onUpdate:modelValue': () => {},
  style: {
    color: 'blue'
  },
  type: 'text'
}

Thank you!

$attrs in Vue 3

By Natalia Tepluhina

$attrs in Vue 3

  • 125
Loading comments...

More from Natalia Tepluhina