DEV Community

Matthew Blewitt
Matthew Blewitt

Posted on

2 2

Reuse component functionality with the Vue wrapper component pattern

When building Vue components I often need to create a component that has similar functionality to an existing base component. I want to re-use the base component and extend it to create a new one. A good pattern for this is the wrapper component.

Think of a BaseButton.vue. It takes some props and emits some events:

<template>
  <button
    :class="`btn btn-${theme}`"
    :disabled="disabled"
    @click="handleClick"
  >
    <slot />
  </button>
</template>

<script>
export default {
  name: "BaseButton",
  props: {
    theme: {
      type: String,
      default: "info",
      validator: val =>
        [
          "info",
          "success",
          "error"
        ].indexOf(val) !== -1
    },
    disabled: {
      type: Boolean,
      default: false
    }
  }
  methods: {
    handleClick() {
      this.$emit("click");
    }
  }
};
</script>

<style scoped>
.btn {
  outline: none;
  border: none;
  color: white;
}
.btn-info {
  background: blue;
}
.btn-success {
  background: green;
}
.btn-error {
  background: red;
}
</style>

I now have a need to build a button that shows a loading state with some text and disables the button when passed a prop of loading. I could cram this new functionality into the BaseButton, but a much cleaner solution is to use a wrapper component pattern. Let's create a LoadingButton.vue.

<template>
  <BaseButton v-bind="{ ...$props, ...$attrs }" v-on="$listeners">
    <template v-if="loading">Loading...</template>
    <slot v-else />
  </BaseButton>
</template>

<script>
import BaseButton from "~/components/BaseButton";
export default {
  components: {
    BaseButon
  },
  props: {
    ...BaseButton.props,
    loading: {
      type: Boolean,
      default: false
    }
  }
};
</script>

A couple of this are happening here:

  • Pass all the components instance details down to the base components via $props, $attr, $listeners. See more Vue in the docs.
  • Use BaseButton.props to maintain the same props passed down but add additional loading prop to create the new functionality.

A great little pattern for component reusability 🔥

Originally posted on https://matthewblewitt.com/posts/vue-wrapper-component

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

đź‘‹ Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay