Button is an extension to standard input element with icons and theming.
npx volt-vue add Button SecondaryButton ContrastButton DangerButton
import Button from '@/volt/Button.vue';
import SecondaryButton from '@/volt/SecondaryButton.vue';
import ContrastButton from '@/volt/ContrastButton.vue';
import DangerButton from '@/volt/DangerButton.vue';
Text to display on a button is defined with the label property.
<template>
<div class="card flex justify-center">
<Button label="Submit" />
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
</script>
Icon of a button is specified with icon property and position is configured using iconPos attribute.
<template>
<div class="card flex flex-col items-center gap-4">
<div class="flex flex-wrap gap-4 justify-center">
<Button icon="pi pi-home" aria-label="Save" />
<Button label="Profile" icon="pi pi-user" />
<Button label="Save" icon="pi pi-check" iconPos="right" />
</div>
<div class="flex flex-wrap gap-4 justify-center">
<Button label="Search" icon="pi pi-search" iconPos="top" />
<Button label="Update" icon="pi pi-refresh" iconPos="bottom" />
</div>
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
</script>
Busy state is controlled with the loading property.
<template>
<div class="card flex justify-center">
<Button type="button" label="Search" icon="pi pi-check" :loading="loading" @click="load" />
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
import { ref } from 'vue';
const loading = ref(false);
const load = () => {
loading.value = true;
setTimeout(() => {
loading.value = false;
}, 2000);
};
</script>
An example of a router link styled as a Volt button.
<template>
<div class="card flex justify-center">
<RouterLink
to="/"
class="bg-primary hover:bg-primary-emphasis active:bg-primary-emphasis-alt text-primary-contrast px-3 py-2 gap-2 rounded-md font-medium focus-visible:outline focus-visible:outline-offset-2 focus-visible:outline-primary"
>Router</RouterLink
>
</div>
</template>
<script setup lang="ts">
</script>
Secondary, Contrast and Danger buttons are available as separate components for severity alternatives.
<template>
<div class="card flex justify-center flex-wrap gap-4">
<Button label="Primary" />
<SecondaryButton label="Secondary" />
<ContrastButton label="Contrast" />
<DangerButton label="Danger" />
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
import ContrastButton from '@/volt/ContrastButton.vue';
import DangerButton from '@/volt/DangerButton.vue';
import SecondaryButton from '@/volt/SecondaryButton.vue';
</script>
When disabled is present, the element cannot be used.
<template>
<div class="card flex justify-center">
<Button label="Submit" disabled />
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
</script>
Raised buttons display a shadow to indicate elevation.
<template>
<div class="card flex justify-center flex-wrap gap-4">
<Button label="Primary" raised />
<SecondaryButton label="Secondary" raised />
<ContrastButton label="Contrast" raised />
<DangerButton label="Danger" raised />
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
import ContrastButton from '@/volt/ContrastButton.vue';
import DangerButton from '@/volt/DangerButton.vue';
import SecondaryButton from '@/volt/SecondaryButton.vue';
</script>
Rounded buttons have a circular border radius.
<template>
<div class="card flex justify-center flex-wrap gap-4">
<Button label="Primary" rounded />
<SecondaryButton label="Secondary" rounded />
<ContrastButton label="Contrast" rounded />
<DangerButton label="Danger" rounded />
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
import ContrastButton from '@/volt/ContrastButton.vue';
import DangerButton from '@/volt/DangerButton.vue';
import SecondaryButton from '@/volt/SecondaryButton.vue';
</script>
Text buttons are displayed as textual elements.
<template>
<div class="card flex justify-center flex-wrap gap-4">
<Button label="Primary" variant="text" />
<SecondaryButton label="Secondary" variant="text" />
<ContrastButton label="Contrast" variant="text" />
<DangerButton label="Danger" variant="text" />
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
import ContrastButton from '@/volt/ContrastButton.vue';
import DangerButton from '@/volt/DangerButton.vue';
import SecondaryButton from '@/volt/SecondaryButton.vue';
</script>
Text buttons can be displayed elevated with the raised option.
<template>
<div class="card flex justify-center flex-wrap gap-4">
<Button label="Primary" variant="text" raised />
<SecondaryButton label="Secondary" variant="text" raised />
<ContrastButton label="Contrast" variant="text" raised />
<DangerButton label="Danger" variant="text" raised />
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
import ContrastButton from '@/volt/ContrastButton.vue';
import DangerButton from '@/volt/DangerButton.vue';
import SecondaryButton from '@/volt/SecondaryButton.vue';
</script>
Outlined buttons display a border without a transparent background.
<template>
<div class="card flex justify-center flex-wrap gap-4">
<Button label="Primary" variant="outlined" />
<SecondaryButton label="Secondary" variant="outlined" />
<ContrastButton label="Contrast" variant="outlined" />
<DangerButton label="Danger" variant="outlined" />
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
import ContrastButton from '@/volt/ContrastButton.vue';
import DangerButton from '@/volt/DangerButton.vue';
import SecondaryButton from '@/volt/SecondaryButton.vue';
</script>
Buttons can have icons without labels.
<template>
<div class="card">
<div class="flex justify-center mb-8">
<SelectButton v-model="size" :options="sizeOptions" optionLabel="label" optionValue="value" dataKey="label" />
</div>
<div class="flex flex-wrap justify-center gap-4 mb-6">
<Button icon="pi pi-check" aria-label="Filter" :size="size" />
<SecondaryButton icon="pi pi-bookmark" severity="secondary" aria-label="Bookmark" :size="size" />
<ContrastButton icon="pi pi-search" severity="success" aria-label="Search" :size="size" />
<DangerButton icon="pi pi-times" severity="info" aria-label="User" :size="size" />
</div>
<div class="flex flex-wrap justify-center gap-4 mb-6">
<Button icon="pi pi-check" aria-label="Filter" :size="size" rounded />
<SecondaryButton icon="pi pi-bookmark" severity="secondary" aria-label="Bookmark" :size="size" rounded />
<ContrastButton icon="pi pi-search" severity="success" aria-label="Search" :size="size" rounded />
<DangerButton icon="pi pi-times" severity="info" aria-label="User" :size="size" rounded />
</div>
<div class="flex flex-wrap justify-center gap-4 mb-6">
<Button icon="pi pi-check" aria-label="Filter" :size="size" variant="outlined" rounded />
<SecondaryButton icon="pi pi-bookmark" severity="secondary" aria-label="Bookmark" :size="size" variant="outlined" rounded />
<ContrastButton icon="pi pi-search" severity="success" aria-label="Search" :size="size" variant="outlined" rounded />
<DangerButton icon="pi pi-times" severity="info" aria-label="User" :size="size" variant="outlined" rounded />
</div>
<div class="flex flex-wrap justify-center gap-4 mb-6">
<Button icon="pi pi-check" aria-label="Filter" :size="size" variant="text" rounded />
<SecondaryButton icon="pi pi-bookmark" severity="secondary" aria-label="Bookmark" :size="size" variant="text" rounded />
<ContrastButton icon="pi pi-search" severity="success" aria-label="Search" :size="size" variant="text" rounded />
<DangerButton icon="pi pi-times" severity="info" aria-label="User" :size="size" variant="text" rounded />
</div>
<div class="flex flex-wrap justify-center gap-4 mb-6">
<Button icon="pi pi-check" aria-label="Filter" :size="size" variant="text" raised rounded />
<SecondaryButton icon="pi pi-bookmark" severity="secondary" aria-label="Bookmark" :size="size" variant="text" raised rounded />
<ContrastButton icon="pi pi-search" severity="success" aria-label="Search" :size="size" variant="text" raised rounded />
<DangerButton icon="pi pi-times" severity="info" aria-label="User" :size="size" variant="text" raised rounded />
</div>
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
import ContrastButton from '@/volt/ContrastButton.vue';
import DangerButton from '@/volt/DangerButton.vue';
import SecondaryButton from '@/volt/SecondaryButton.vue';
import SelectButton from '@/volt/SelectButton.vue';
import { ref } from 'vue';
const size = ref('normal');
const sizeOptions = ref([
{ label: 'Small', value: 'small' },
{ label: 'Normal', value: 'normal' },
{ label: 'Large', value: 'large' }
]);
</script>
Buttons have built-in badge support with the badge property.
<template>
<div class="card flex justify-center flex-wrap gap-4">
<Button type="button" label="Emails" badge="2" />
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
</script>
Multiple buttons are grouped when wrapped inside an element with ButtonGroup component.
<template>
<div class="card flex flex-col items-center gap-6">
<ButtonGroup>
<Button label="Save" icon="pi pi-check" />
<Button label="Delete" icon="pi pi-trash" />
<Button label="Cancel" icon="pi pi-times" />
</ButtonGroup>
<ButtonGroup>
<Button label="Save" icon="pi pi-check" variant="outlined" />
<Button label="Delete" icon="pi pi-trash" variant="outlined" />
<Button label="Cancel" icon="pi pi-times" variant="outlined" />
</ButtonGroup>
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
import ButtonGroup from '@/volt/ButtonGroup';
</script>
Button provides small and large sizes as alternatives to the base.
<template>
<div class="card flex flex-wrap items-center justify-center gap-4">
<Button label="Small" icon="pi pi-check" size="small" />
<Button label="Normal" icon="pi pi-check" />
<Button label="Large" icon="pi pi-check" size="large" />
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
</script>
Custom content inside a button is defined as children.
<template>
<div class="card flex justify-center">
<Button variant="outlined" class="!border-2">
<svg width="35" height="40" viewBox="0 0 35 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M25.87 18.05L23.16 17.45L25.27 20.46V29.78L32.49 23.76V13.53L29.18 14.73L25.87 18.04V18.05ZM25.27 35.49L29.18 31.58V27.67L25.27 30.98V35.49ZM20.16 17.14H20.03H20.17H20.16ZM30.1 5.19L34.89 4.81L33.08 12.33L24.1 15.67L30.08 5.2L30.1 5.19ZM5.72 14.74L2.41 13.54V23.77L9.63 29.79V20.47L11.74 17.46L9.03 18.06L5.72 14.75V14.74ZM9.63 30.98L5.72 27.67V31.58L9.63 35.49V30.98ZM4.8 5.2L10.78 15.67L1.81 12.33L0 4.81L4.79 5.19L4.8 5.2ZM24.37 21.05V34.59L22.56 37.29L20.46 39.4H14.44L12.34 37.29L10.53 34.59V21.05L12.42 18.23L17.45 26.8L22.48 18.23L24.37 21.05ZM22.85 0L22.57 0.69L17.45 13.08L12.33 0.69L12.05 0H22.85Z"
fill="var(--p-primary-color)"
/>
<path
d="M30.69 4.21L24.37 4.81L22.57 0.69L22.86 0H26.48L30.69 4.21ZM23.75 5.67L22.66 3.08L18.05 14.24V17.14H19.7H20.03H20.16H20.2L24.1 15.7L30.11 5.19L23.75 5.67ZM4.21002 4.21L10.53 4.81L12.33 0.69L12.05 0H8.43002L4.22002 4.21H4.21002ZM21.9 17.4L20.6 18.2H14.3L13 17.4L12.4 18.2L12.42 18.23L17.45 26.8L22.48 18.23L22.5 18.2L21.9 17.4ZM4.79002 5.19L10.8 15.7L14.7 17.14H14.74H15.2H16.85V14.24L12.24 3.09L11.15 5.68L4.79002 5.2V5.19Z"
fill="var(--p-text-color)"
/>
</svg>
</Button>
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
</script>
Headless mode is enabled by adding the asChild property and defining your own UI element with the available bindings.
<template>
<div class="card flex justify-center">
<Button v-slot="slotProps" asChild>
<button
v-bind="slotProps.a11yAttrs"
class="rounded-lg bg-gradient-to-br from-primary-400 to-primary-700 active:from-primary-700 active:to-primary-900 text-white border-none px-6 py-3 font-bold hover:ring-2 cursor-pointer ring-offset-2 ring-offset-surface-0 dark:ring-offset-surface-900 ring-primary transition-all"
>
SIGN UP
</button>
</Button>
</div>
</template>
<script setup lang="ts">
import Button from '@/volt/Button.vue';
</script>
Key distinctions to notice between the Volt Button and the PrimeVue Button.