QButton component
QButton is used to trigger actions or to display links. It includes a variety of classes to customize appearance.
Styling
Available variants
To be assigned with variant
binding
primary
: Uses CSS color --accent-color-primarysecondary
: Uses CSS color --accent-color-secondaryinfo
: Uses CSS color --color-infosuccess
: Uses CSS color --color-successwarning
: Uses CSS color --color-warningerror
: Uses CSS color --color-errordark
: Uses CSS color --black-colorbright
: Uses CSS color --white-color
Available coloring
Background coloring
To be assigned with bgColor
binding
primary
Uses the--accent-color-primary
CSS variablesecondary
Uses the--accent-color-secondary
CSS variable
Text coloring
To be assigned with textColor
binding
If undefined, the text color will depend on the color theme
bright
Uses the--accent-color-primary
CSS variabledark
Uses the--accent-color-secondary
CSS variable
Requirements
Type | Path / Version | Purpose | Optional |
---|---|---|---|
Styles | ../../assets/main.css | CSS Variables | No |
Functions | ../../use/uuid | Assign ids to items | No |
Usage
Import the following component/s:
import QButton from '../../components/Form/QButton.vue'
Basic usage
By default, the button has the defined primary color set. The text color switches with the currently active theme, the label & the loader are toggled based on whether loading
is set to true or false
Loader idle
Example
<template>
<q-button label="Submit form" :loading="isLoading" @click="onButtonClick" />
<p v-if="isLoading && loadingCounter > 1">Done in {{loadingCounter}} seconds ...</p>
<p v-else-if="isLoading && loadingCounter === 1">Almost there ...</p>
<p v-else>Loader idle</p>
</template>
<script setup>
import { ref } from 'vue';
let isLoading = ref(false);
let loadingCounter = ref(3)
const onButtonClick = () => {
isLoading.value = true
loadingCounter.value = 3;
const countdown = setInterval(() => {
loadingCounter.value -= 1;
if(loadingCounter.value <= 0) {
isLoading.value = false
return clearInterval(countdown)
}
}, 1000)
}
</script>
Variants & sizing
Coloring and sizing can be customized using variant
and size
bindings.
Small sizing | Added by size="small"
Example
<template>
<q-button variant="info" size="small" label="Info" :loading="isLoading" @click="onButtonClick" />
</template>
Default sizing | Default setting
Example
<template>
<q-button variant="info" size="medium" label="Info" :loading="isLoading" @click="onButtonClick" />
</template>
Large sizing
Example
<template>
<q-button variant="info" size="large" label="Info" :loading="isLoading" @click="onButtonClick" />
</template>
XL sizing
Example
<template>
<q-button variant="info" size="xlarge" label="Info" :loading="isLoading" @click="onButtonClick" />
</template>
Loader idle
Full width | Added by fluid
binding:
Example
<template>
<q-button variant="info" fluid label="Info" :loading="isLoading" @click="onButtonClick" />
</template>
Wave effect
Once registered, you can use the v-ripple
- directive on these buttons, making them resemble their material design counterparts. Read more about ripple effects here
Full component's code
QButton
<template>
<button
class="q-button-base"
:id="id"
:disabled="loading"
:aria-disabled="loading"
:aria-busy="loading"
:class="{
'q-button-u-full-width': fluid === true,
'q-button-u-disabled': loading,
'q-button-v-primary': variant === 'primary',
'q-button-v-secondary': variant === 'secondary',
'q-button-v-info': variant === 'info',
'q-button-v-success': variant === 'success',
'q-button-v-warning': variant === 'warning',
'q-button-v-error': variant === 'error',
'q-button-v-link': variant === 'link',
'q-button-s-small': size === 'small',
'q-button-s-medium': size === 'medium',
'q-button-s-large': size === 'large',
'q-button-s-xlarge': size === 'xlarge',
}"
>
<i v-if="loading">
<div class="loader"></div>
</i>
<span v-else>{{ label }}</span>
</button>
</template>
<script setup>
import uuid from "../../use/uuid";
const id = uuid();
defineProps({
loading: {
type: Boolean,
default: false,
},
label: {
type: String,
required: true,
default: "",
},
fluid: {
type: Boolean,
default: false,
},
variant: {
type: String,
required: false,
default: "primary",
validator(value) {
const isPrimary = value === "primary";
const isSecondary = value === "secondary";
const isInfo = value === "info";
const isSuccess = value === "success";
const isWarning = value === "warning";
const isError = value === "error";
const isDark = value === "dark";
const isBright = value === "bright";
return (
isPrimary ||
isSecondary ||
isInfo ||
isSuccess ||
isWarning ||
isError ||
isDark ||
isBright
);
},
},
size: {
type: String,
default: "medium",
validator(value) {
const isSmall = value === "small";
const isMedium = value === "medium";
const isLarge = value === "large";
const isXlarge = value === "xlarge";
return isSmall || isMedium || isLarge || isXlarge;
},
},
});
</script>
<style scoped>
.q-button-base {
border: none;
border-radius: var(--gap-xs);
cursor: pointer;
margin: var(--gap-sm) var(--gap-sm) var(--gap-sm) 0;
text-align: center;
font-weight: 600;
}
/* Util classes for the button */
.q-button-u-fluid {
width: 100%;
margin: 0;
}
.q-button-base.q-button-u-full-width {
display: block;
width: 100%;
}
.q-button-u-disabled {
opacity: var(--opacity-disabled);
}
/* Variant classes */
.q-button-v-primary {
background-color: var(--accent-color-primary);
}
.q-button-v-secondary {
background-color: var(--accent-color-secondary);
}
.q-button-v-info {
background-color: var(--color-info);
color: var(--white-color);
}
.q-button-v-success {
background-color: var(--color-success);
color: var(--white-color);
}
.q-button-v-warning {
background-color: var(--color-warning);
color: var(--white-color);
}
.q-button-v-error {
background-color: var(--color-error);
color: var(--white-color);
}
.q-button-v-primary .loader,
.q-button-v-secondary .loader {
border-top: 2px solid var(--background-color-tartiary);
}
.q-button-v-info .loader,
.q-button-v-success .loader,
.q-button-v-warning .loader,
.q-button-v-error .loader {
border-top: 2px solid var(--white-color);
}
.q-button-v-link {
background-color: transparent !important;
padding: var(--gap-sm);
color: var(--accent-color-primary) !important;
font-size: var(--text-size-sm);
width: fit-content;
}
.q-button-v-link:hover {
text-decoration: underline;
}
/* Sizing classes */
.q-button-s-small {
padding: var(--gap-sm) var(--gap-lg);
font-size: var(--text-size-xs);
width: var(--el-size-sm);
}
.q-button-s-small .loader {
width: var(--text-size-xs);
height: var(--text-size-xs);
}
.q-button-s-medium {
padding: var(--gap-sm) var(--gap-xl);
font-size: var(--text-size-sm);
width: var(--el-size-md);
}
.q-button-s-medium .loader {
width: var(--text-size-sm);
height: var(--text-size-sm);
}
.q-button-s-large {
padding: var(--gap-md) var(--gap-xxl);
font-size: var(--text-size-md);
height: var(--el-size-xxs);
width: var(--el-size-lg);
}
.q-button-s-large .loader {
width: var(--text-size-md);
height: var(--text-size-md);
}
.q-button-s-xlarge {
padding: var(--gap-md) var(--gap-xxl);
font-size: var(--text-size-lg);
height: var(--el-size-xs);
width: var(--el-size-xl);
}
.q-button-s-xlarge .loader {
width: var(--text-size-lg);
height: var(--text-size-lg);
}
/* Text color classes */
.q-button-c-text-bright {
color: var(--white-color) !important;
}
.q-button-c-text-dark {
color: var(--black-color) !important;
}
/* Styles for the loader */
.loader {
display: block;
margin: auto;
padding: var(--gap-xs);
border-radius: 50%;
border-right: 2px solid transparent;
animation: fullRotation var(--duration-semi) linear infinite;
}
@keyframes fullRotation {
to {
transform: rotate(360deg);
}
}
</style>