Today we are going to build a custom button component using Vue and Tailwindcss. Here you can look into my codepen.
As you have seen, I have kept different options for the colors, size, and roundness of the button. By default this button ships with a loading spinner. You could use the loading feature when you are waiting for the promise to return from axios.
It follows three steps -
Creating the Button Component
Create a file called LoadingButton.vue
in /src/Shared/LoadingButton.vue
and add
//LoadingButton.vue
<template>
<component
:is="tag"
:type="type"
v-on="$listeners"
:disabled="disableButton"
:class="[btnClass, colorVariants]"
:variant="variant"
:variant-type="variantType"
:size="size"
:href="to"
>
<slot />
</component>
</template>
<script>
export default {
name: "LoadingButton",
props: {
tag: {
type: String,
default: "button"
},
disabled: {
type: Boolean,
default: false
},
variant: {
type: String,
default: "primary"
},
variantType: {
type: String,
default: "normal"
},
size: {
type: String,
default: "normal"
},
rounded: {
type: String,
default: "medium"
},
type: {
type: String,
default: ""
},
to: {
type: String
}
},
data() {
return {
loading: false,
disableButton: this.disabled
};
},
methods: {
startLoading() {
this.loading = true;
this.disableButton = true;
},
stopLoading() {
this.loading = false;
this.disableButton = false;
}
},
computed: {
btnClass() {
return {
"base-spinner": this.loading == true,
"cursor-not-allowed": this.disableButton == true,
"base-button inline-flex align-middle align-items-center justify-center font-medium focus:outline-none border-2": true,
"rounded-lg": this.rounded === "medium",
"rounded-full": this.rounded === "large",
"px-6 py-3": this.size == "normal",
"px-4 py-2": this.size == "small"
};
},
colorVariants() {
switch (this.variant) {
case "primary":
switch (this.variantType) {
case "normal":
switch (this.disableButton) {
case true:
return "border-blue-300 bg-blue-300 text-white";
break;
default:
break;
}
return "border-blue-600 bg-blue-600 hover:bg-blue-700 hover:border-blue-700 text-white";
break;
case "outline":
return "border-gray-200 text-blue-500 hover:text-blue-700";
break;
default:
break;
}
break;
case "danger":
switch (this.variantType) {
case "normal":
switch (this.disableButton) {
case true:
return "border-red-300 bg-red-300 text-white";
break;
default:
break;
}
return "border-red-600 bg-red-600 hover:bg-red-700 hover:border-red-700 text-white";
break;
case "outline":
return "border-gray-200 text-red-500 hover:text-red-600";
break;
default:
break;
}
break;
case "warning":
switch (this.variantType) {
case "normal":
return "border-orange-600 bg-orange-600 hover:bg-orange-700 hover:border-orange-700 text-white";
break;
default:
break;
}
break;
case "success":
switch (this.variantType) {
case "normal":
switch (this.disableButton) {
case true:
return "border-green-300 bg-green-300 text-white";
break;
default:
break;
}
return "border-green-600 bg-green-600 hover:bg-green-700 hover:border-green-700 text-white";
break;
case "outline":
return "border-2 border-gray-200 text-green-500 hover:text-green-700";
break;
default:
break;
}
break;
case "white":
switch (this.variantType) {
case "normal":
return "border-white bg-white text-blue-600 hover:text-blue-800";
break;
default:
break;
}
break;
case "secondary":
switch (this.variantType) {
case "outline":
return "border-gray-300 text-gray-500 hover:text-blue-500";
break;
default:
break;
}
break;
default:
break;
}
}
}
};
</script>
Using the component
Now, we will use the loading-button
component in our App.vue
.
// App.vue
<template>
<div id="app">
<loading-button @click="submit" ref="submitButton">Save Changes</loading-button>
</div>
</template>
<script>
import LoadingButton from "@/Shared/LoadingButton";
export default {
name: "app",
components: {
LoadingButton
},
methods: {
submit() {
//calling the startLoading method of the button, which enables the button to loading state
this.$refs.submitButton.startLoading();
}
}
};
</script>
Using the props
default option
Name | Type | Description | Accepted |
---|---|---|---|
variant | String | Color scheme of the button |
primary , danger, success, warning, secondary |
variant-type | String | Normal button or ghost button |
normal , outline |
rounded | String | border radius of the button |
medium , large |
size | String | padding of the button |
normal , small |
Methods Available
default option
Name | Description |
---|---|
startLoading | start loading state of the button |
stopLoading | stop loading state of the button |
N.B.
- Only primary, danger and success variant accepts a disabled prop.
- secondary variant is only available for outline button.
Top comments (0)