Skip to content

PrimeVue Button with FontAwesome Icons

🔎 Info

Before you start, make sure you have all necessary dependencies installed:

  1. PrimeVue - Installation guide for Vue 3
  2. Tailwind Css - Installation guide for Vue 3
  3. Fontawesome Icons - Installation guide for Vue 3

⚠️ Additionally, you need to add the icon fa-spinner into your Fontawesome Icon Library.


This guide was made for PrimeVue v3.46.0

1. Add a custom component

vue
<template>
  <Button
    class="max-h-8"
    v-bind="$attrs"
    :loading="loading">
    <div
      v-if="iconPosition === ButtonIconPosition.Left && icon"
      :class="{
        'spinner': loading,
        'mr-2': !!label
      }">
      <FontAwesomeIcon :icon="iconToDisplay" />
    </div>
    <span v-if="label">
      {{ label }}
    </span>
    <div
      v-if="iconPosition === ButtonIconPosition.Right && icon"
      class="ml-2"
      :class="{
        'spinner': loading,
        'ml-2': !!label
      }">
      <FontAwesomeIcon :icon="iconToDisplay" />
    </div>
  </Button>
</template>


<script setup lang="ts">
  import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
  import Button from 'primevue/button';
  import { computed, type PropType, toRefs } from 'vue';

  export enum ButtonIconPosition {
    Left = 'left',
    Right = 'right'
  }

  const props = defineProps({
    icon: {
      type: String,
      default: ''
    },
    loadingIcon: {
      type: String,
      default: 'fa-spinner'
    },
    loading: {
      type: Boolean,
      default: false
    },
    iconPosition: {
      type: String as PropType<ButtonIconPosition>,
      default: ButtonIconPosition.Left
    },
    label : {
      type: String,
      default: ''
    }
  });

  const { icon, loadingIcon, loading, iconPosition } = toRefs(props);

  const iconToDisplay = computed((): string => {
    if (loadingIcon.value && loading.value) {
      return loadingIcon.value;
    } else {
      return icon.value;
    }
  });
</script>

<style lang="scss">
/* Custom spinner animation for loading state */
@-webkit-keyframes rotating /* Safari and Chrome */ {
  from {
    -webkit-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  to {
    -webkit-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@keyframes rotating {
  from {
    -ms-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -webkit-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  to {
    -ms-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -webkit-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
.spinner {
  -webkit-animation: rotating 2s linear infinite;
  -moz-animation: rotating 2s linear infinite;
  -ms-animation: rotating 2s linear infinite;
  -o-animation: rotating 2s linear infinite;
  animation: rotating 2s linear infinite;
}
</style>

2. Add component to main.ts for global access

typescript
//main.ts

import App from './App.vue';

// import custom button component
import ButtonWithIcon from '@/components/elements/ButtonWithIcon.vue';
// eslint-disable-next-line vue/no-reserved-component-names,vue/multi-word-component-names
app.component('Button', ButtonWithIcon);

3. Use component in your Code!

vue

<template>
  ...
  <Button
      label="Attachments"
      icon="fa-paperclip"
      size="small">
  </Button>
  ...
</template>