Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use vue-fontawesome for checkbox checkmark?

I'm using vue-fontawesome together with font-awesome-icon. This works great for "standalone" icons like so:

<font-awesome-icon :icon="icon" size="1x" /> .

But how can I use the fontawesome checkmark for an <input type="checkbox"> in the vue component way?

like image 837
fantastischIdee Avatar asked Feb 13 '18 14:02

fantastischIdee


2 Answers

There is a way to look for css pseudo-elements:

FontAwesomeConfig = { searchPseudoElements: true };

This method is not recommended since it will examine existing markup and through CSS styling add inline SVG for pseudo-elements, which is slow.

I do not encourage this method so I will not explain how it works, if you're interested you can read more about it here.


Instead of using pseudo-elements, create a component for these checkboxes.

We will create a Single File Component called awesome-checkbox.

AwesomeCheckbox.vue

<template>
  <div :class="{'awesome-checkbox': true, [wrapperClassName]: !!wrapperClassName}"
       :style="{ color: isChecked ? checkedColor : uncheckedColor }">
    <input :id="id"
           :name="name"
           type="checkbox"
           class="awesome-checkbox__input"
           v-model="checkboxModel">
    <label :for="id"
           :style="{ cursor }"
           class="awesome-checkbox__label"
           @click="toggleCheck">
      <font-awesome-icon :icon="isChecked ? checkedIcon : uncheckedIcon"
                         :size="size" />
    </label>
  </div>
</template>

<script>
import FontAwesomeIcon from '@fortawesome/vue-fontawesome';
import { faSquare, faCheckSquare } from '@fortawesome/fontawesome-free-solid';

/**
 * Custom HTML <input> checkbox element using Font-Awesome-Icon 5 icons for visual effect.
 */
export default {
  name: 'awesome-checkbox',

  components: { FontAwesomeIcon },

  props: {
    /**
     * A wrapper class other than default that provides extra manipulation from parent component.
     */
    wrapperClassName: {
      type: String,
      default: null,
    },
    /**
     * The name attribute for the checkbox input.
     */
    name: {
      type: String,
      default: null,
    },
    /**
     * The id attribute for the checkbox input.
     */
    id: {
      type: String,
      default: null,
      required: true,
    },
    /**
     * The model directive value to create two-way data binding.
     */
    model: {
      type: Boolean,
      default: null,
      required: true,
    },
    /**
     * The mouse cursor to display when the mouse pointer is over the Font-Awesome-Icon 5 element.
     * Accepts any cursor CSS property value.
     */
    cursor: {
      type: String,
      default: 'pointer',
    },
    /**
     * The Font-Awesome-Icon 5 imported icon object used for the unchecked state.
     */
    uncheckedIcon: {
      type: Object,
      default: () => faSquare,
    },
    /**
     * The Font-Awesome-Icon 5 imported icon object used for the checked state.
     */
    checkedIcon: {
      type: Object,
      default: () => faCheckSquare,
    },
    /**
     * The Font-Awesome-Icon 5 icon size.
     */
    size: {
      type: String,
      default: '1x',
    },
    /**
     * The Font-Awesome-Icon 5 icon color used for the unchecked state.
     */
    uncheckedColor: {
      type: String,
      default: 'inherit',
    },
    /**
     * The Font-Awesome-Icon 5 icon color used for the checked state.
     */
    checkedColor: {
      type: String,
      default: 'inherit',
    },
  },

  data() {
    return {
      isChecked: !!this.model,
      checkboxModel: this.model,
    };
  },

  methods: {
    emitModelValueUpdate() {
      /**
       * Update event.
       *
       * @event update
       * @type {boolean}
       */
      this.$emit('update:model', this.isChecked);
    },
    /**
     * Gets called when the user clicks on the label element.
     */
    toggleCheck() {
      this.isChecked = !this.isChecked;
      this.emitModelValueUpdate();
    },
  },
};
</script>

<style lang="scss" scoped>
.awesome-checkbox {
  display: inline-flex;

  &__label {
    font-size: 1em; // Change Font-Awesome-Icon 5 icon size with css instead of predefined Font-Awesome-Icon 5 size prop.
  }

  &__input {
    display: none; // Hide the HTML <input> element.
  }
}
</style>

And use it in a parent component like so:

<template>
  <div>
    <awesome-checkbox :model.sync="acceptTerms"
                      checkedColor="#41B883"
                      uncheckedColor="#E0EAF1"
                      cursor="pointer"
                      size="1x"
                      id="my-awesome-checkbox"
                      name="acceptTerms"
                      :checkedIcon="faCheckSquare"
                      :uncheckedIcon="faSquare" />
  </div>
</template>

<script>
import { faSquare, faCheckSquare } from '@fortawesome/fontawesome-free-solid';
import AwesomeCheckbox from '@/components/path/to/AwesomeCheckbox';

export default {
  name: 'parent-component',

  components: { AwesomeCheckbox },

  data() {
    return {
      acceptTerms: false,
      faSquare,
      faCheckSquare,
    };
  },
};
</script>

<style lang="scss" scoped>
/* ... */
</style>

You can extend this component to your needs, like making the model prop accept more than one type, like an Array instead of a boolean.

I just made this component for your question and have not tested it fully, please use it carefully.

like image 155
Ricky Avatar answered Oct 25 '22 17:10

Ricky


Using all of Ricky's effort but in typescript for those who might be looking, as I was.

The Checkbox

<template>
  <div :class="{'awesome-checkbox': true, [wrapperClassName]: !!wrapperClassName}"
       :style="{ color: checked ? checkedColor : uncheckedColor }">
    <input :id="id"
           :name="name"
           type="checkbox"
           class="awesome-checkbox__input"
           v-model="checked">
    <label :for="id"
           :style="{ cursor }"
           class="awesome-checkbox__label"
           @click="toggleCheck">
      <font-awesome-icon :icon="checked ? checkedIcon : uncheckedIcon"
                         :size="size" />
    </label>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { faSquare, faCheckSquare } from '@fortawesome/fontawesome-free-solid';

@Component

export default class Checkbox extends Vue {
  @Prop({default: null})
  wrapperClassName!: string;

  @Prop({default: null})
  name!: string;

  @Prop({default: null, required: true})
  id!: string;

  @Prop({default: null, required: true})
  model!: Boolean;

  @Prop({default: 'pointer'})
  cursor!: string;

  @Prop({default: () => faSquare})
  uncheckedIcon!: Object;

  @Prop({default: () => faCheckSquare})
  checkedIcon!: Object;

  @Prop({default: '1x'})
  size!: string;

  @Prop({default: 'inherit'})
  uncheckedColor!: string;

  @Prop({default: 'inherit'})
  ucheckedColor!: string;

  private emitModelValueUpdate() {
    /**
     * Update event.
     *
     * @event update
     * @type {boolean}
     */
    this.$emit('update:model', this.$data.checked);
  }
  private toggleCheck() {
    this.$data.checked = !this.$data.checked;
    this.emitModelValueUpdate();
  }

  constructor() {
    super();
  }

  public data() {
    return {
      checked: false,
    };
  }

}
</script>

<style lang="scss" scoped>
.awesome-checkbox {
  display: inline-flex;

  &__label {
    font-size: 1em; // Change Font-Awesome-Icon 5 icon size with css instead of predefined Font-Awesome-Icon 5 size prop.
  }

  &__input {
    display: none; // Hide the HTML <input> element.
  }
}
</style>

The Parent

<template>
  <div class="content">
    <b-row>      
      <b-col>
        <Checkbox />
      </b-col>
    </b-row>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import Checkbox from '@/components/forms/Checkbox.vue';

@Component({
  components: {
    Checkbox,
  },
})

export default class DevHelper extends Vue {
  @Prop() private msg!: string;
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">

</style>

Hope it helps.

like image 44
K7Buoy Avatar answered Oct 25 '22 18:10

K7Buoy