DEV Community

Cover image for Use Bulma and FontAwesome 5 with Nuxt.js
Matthew Piercey for OverScore Media

Posted on

Use Bulma and FontAwesome 5 with Nuxt.js

So, you created a new boilerplate site using Nuxt.js. Now what?

Well, maybe you'll want to use a CSS framework to get started with styling your site. Sure, using a framework comes with its own set of advantages and disadvantages, but honestly it can be a great place to start.

If you haven't heard of Bulma yet, I recommend checking it out, since it's pretty awesome. Its class names make a lot of sense, it comes with a good number of components and prefabs out-of-the-box, but not too many that it can be overwhelming if you haven't used it before (looking at you, Vuetify... OK, Vuetify's great too, and it's definitely worth spending the time to get used to it, but this article's about Bulma, so there.)

Anyway, once you have your site all set-up, open up your favourite code editor in your site's project folder, and add Bulma to your package.json:

$ yarn add bulma
Enter fullscreen mode Exit fullscreen mode

Next, you're going to want to add Bulma to your site by importing it. There are actually a few ways of doing this, but the way I'm going to explain it seemed to work for me, so feel free to follow along.

  1. Create a main.scss file in your site's assets/scss/ folder.
  2. Import Bulma's utilities file with the following line of code:
@import "~bulma/sass/utilities/_all";
Enter fullscreen mode Exit fullscreen mode
  1. Add your customizations (like custom brand colours, in this case - see https://bulma.io/documentation/customize/ for more info):
/* Custom colours:
   (These are what we use on our website,
   https://overscorestudios.ml,
   so feel free to experiment with your own
   colours/variables - see https://bulma.io/documentation/customize/
*/

$primary: hsl(242, 100%, 76%);
$primary-invert: findColorInvert($primary);

$info: hsl(337, 55%, 58%);
$info-invert: findColorInvert($info);

$light: hsl(275, 20%, 83%);
$light-invert: findColorInvert($light);

$dark: hsl(0, 0%, 15%);
$dark-invert: findColorInvert($dark);

$link: hsl(242, 100%, 76%);
$link-invert: findColorInvert($link);

$link-hover: hsl(229, 19%, 66%);
$link-focus: hsl(229, 19%, 66%);

$strong-color: hsl(229, 19%, 66%);

$colors: (
    "white": ($white, $black),
    "black": ($black, $white),
    "link": ($link, $link-invert),
    "light": ($light, $light-invert),
    "dark": ($dark, $dark-invert),
    "primary": ($primary, $primary-invert),
    "info": ($info, $info-invert),
    "success": ($success, $success-invert),
    "warning": ($warning, $warning-invert),
    "danger": ($danger, $danger-invert)
);

Enter fullscreen mode Exit fullscreen mode
  1. Import the rest of Bulma:
// The rest of Bulma
@import '~bulma';
Enter fullscreen mode Exit fullscreen mode
  1. Get Nuxt to import your custom styles in all of your custom .Vue files by installing @nuxtjs/style-resources:
$ yarn add @nuxtjs/style-resources
Enter fullscreen mode Exit fullscreen mode
  1. Finally, get Nuxt to recognize your main.scss file by editing the nuxt.config.js file in two places:
  css: [
    '~/assets/scss/main.scss',
  ],

  // ^ Add your main.scss file to Nuxt's Global CSS array
Enter fullscreen mode Exit fullscreen mode
  modules: [
    '@nuxtjs/style-resources'
  ]

  // ^ Make sure to add @nuxtjs/style-resources to Nuxt's modules array
  // (Remember to add a comma if you have more than one module already)
Enter fullscreen mode Exit fullscreen mode

Cool Beans

Now, without any additional finagling, you should be able to use all of Bulma's classes - along with any custom colours - in your .Vue components!

Speaking of which, let's create some components for FontAwesome 5 icons!

Font Whosome?

FontAwesome 5 is a free/premium icon font, one that's super-popular and used on a lot of sites. It includes icons for a lot of major brands, emoji, and a plethora of others that will undoubtedly be useful while you're building your site.

Again, there are a lot of ways to go about adding FontAwesome 5 to your Nuxt site, and if you out there in Internet-land have any suggestions for alternative methods, leave them in the comments below. :]

The big import

In order to use FontAwesome, you'll have to import it. In this case, we'll be using the SVG icon set they offer, though there's also a webfont and a few other things.

Here's the command to install the Node packages you'll need:

$ yarn add @fortawesome/fontawesome-svg-core &&
$ yarn add @fortawesome/free-brands-svg-icons &&
$ yarn add @fortawesome/free-solid-svg-icons &&
$ yarn add @fortawesome/vue-fontawesome &&
$ yarn add nuxt-fontawesome
Enter fullscreen mode Exit fullscreen mode

Feel free to add all of the packages using the same command; it just is easier to show them like this. Basically, you'll need FontAwesome 5 Free's packages for SVG brand/solid icons, as well as their importer packages (for JavaScript in general, and for Vue and Nuxt in specific).

Now, add nuxt-fontawesome to your nuxt.config.js modules list:

  modules: [
    '@nuxtjs/style-resources',
    'nuxt-fontawesome' // Imports FontAwesome 5 SVG icons
  ]
Enter fullscreen mode Exit fullscreen mode

Next, add an array to your nuxt.config.js that looks something like this:

  fontawesome: {
    imports: [
      {
        set: '@fortawesome/free-solid-svg-icons', // Solid icons
        icons: ['faCookieBite', 'faCommentDots', 'faEnvelope', 'faGrinWink', 'faHeart']
      },
      {
        set: '@fortawesome/free-brands-svg-icons', // Brand icons
        icons: ['faDev', 'faFacebook', 'faTwitter', 'faInstagram', 'faYoutube', 'faGithub']
      }
    ]
  },
Enter fullscreen mode Exit fullscreen mode

Now, you may have noticed that in the above code snippet, I imported a few icons from the Solid set and the Brands set. You technically can import all of them, but I'd really advise against it (unless for some inane reason you actually needed all of them), since keeping your imports smaller keeps your site's bundle size smaller, and your load-times faster!

That being said, you can look up what icons you want to use on FontAwesome's website. Make sure you import any icons using the following schema:

Icon Name: adobe
Import Name: faAdobe (in the brands icons array)

Icon Name: align-left
Import Name: faAlignLeft (in the solid icons array)
Enter fullscreen mode Exit fullscreen mode

If you can't seem to get the hang of it, you can always peer into the murky depths of your site's node_modules folder, in the @fortawesome/free-brands-svg-icons/ or @fortawesome/free-solid-svg-icons folder, and look for the name of the icon you want to import - you'll notice two of each because TypeScript exists and each icon's JS file has a corresponding TypeScript definition file.

Almost There!

Now, you imported the icons, but how do you make them work in your .Vue files?

I chose to create custom components for them, Fas.vue for solid icons and Fab.vue for brand icons:

<!--- components/Fas.vue -->

<!---
  FontAwesome 5 Free Solid Icon Component

  Usage Example:

  <Fas i="arrow-down" />

  Props:
  - i: The FontAwesome 5 Free Solid icon name (like "arrow-up" or "ad")
  - classes: CSS classes to add to the icon

  Caveats:
  - Each icon has to be pre-loaded in nuxt.config.js or it won't show up

-->
<template>
  <font-awesome-icon :class="`${classes}`" :icon="['fas', i]" />
</template>

<script>
export default {
  props: {
    i: {
      type: String,
      required: true,
      default: 'arrow-down'
    },
    classes: {
      type: String,
      required: false,
      default: 'icon is-medium'
    }
  }
}
</script>

Enter fullscreen mode Exit fullscreen mode
<!--- components/Fab.vue -->

<!---
  FontAwesome 5 Free Brands Icon Component

  Usage Example:

  <Fab i="facebook" />

  Props:
  - i: The FontAwesome 5 Free Brands icon name (like "twitter" or "reddit")
  - classes: CSS classes to add to the icon

  Caveats:
  - Each icon has to be pre-loaded in nuxt.config.js or it won't show up

-->
<template>
  <font-awesome-icon :class="`${classes}`" :icon="['fab', i]" />
</template>

<script>
export default {
  props: {
    i: {
      type: String,
      required: true,
      default: 'facebook'
    },
    classes: {
      type: String,
      required: false,
      default: 'icon is-medium'
    }
  }
}
</script>

Enter fullscreen mode Exit fullscreen mode

Is it worth explaining exactly how/why these work? Well, probably not. I really don't think I'm great at teaching Vue to someone who's completely new to it, though I can say that it only took me about 3 months to get confident with using Vue, fiddling around with it on/off. Honestly, it wasn't until I started using Nuxt that it all began to click, and in a couple weeks of off/on experimenting I think I have a pretty good idea of how it works.

My advice to Vue-newbies is honestly to just try building a website from scratch using Vue (or Nuxt, since I really think it does much of the "dirty work" for you, allowing you to focus on writing quality, readable, testable, powerful code). If you already know how to build a website, then it shouldn't be too hard - just get there and try it. If you don't know where to start, I can't recommend FreeCodeCamp enough.

But how though?

Here's an example of a Fab.vue component being used in the wild:

<a href="https://facebook.com/overscorestudios" target="_blank" rel="noreferrer" aria-label="Like us on Facebook">
  <Fab i="facebook" />
</a>
Enter fullscreen mode Exit fullscreen mode

Don't forget to import all custom components in your page/component/layout's <script> tag:

import Fab from '~/components/Fab.vue

export default {
  components: {
    Fab
  }
}
Enter fullscreen mode Exit fullscreen mode

And, you might have noticed that I added an aria-label to the <a> tag in which the <Fab /> was. I'm pretty sure this does what I want it to do - namely, allow screen-reader users to understand what the icon they can't see actually means. Again, I'm no expert on any of this, but from what I can tell it does its job. Make sure to always have accessible fallbacks like that for icons. If they're just decorative, I guess you probably don't need them, but if they are for buttons/links or anything interactive, or if they are important in the context of your page somehow, they really should have aria-labels or something like that. Again, feel free to discuss in the comments.

Well, there you have it! Bulma and FontAwesome should be up-and-running!

Next, I'll cover how to get PurgeCSS to work (to keep your bundle sizes small), how to add a cookie consent banner (and ethical tracking with Matomo), how to add Anime.js (for nifty animations), Typed.js (for typing animations), and Prism.js (for syntax highlighting) to your site, and how to add a news page with Netlify CMS - among other things.

In the mean time, if you're following along and creating a site of your own, it's probably about time to make a Git commit:

git add .
git commit -am "Add Bulma CSS and FontAwesome 5"
git push
Enter fullscreen mode Exit fullscreen mode

Top comments (11)

Collapse
 
codeboje profile image
Jens@MindfulDevMag

Thanks.

I only need the first part, however, to get that working I had to install the sass loader too.

npm install --save-dev node-sass sass-loader

Collapse
 
mtpiercey profile image
Matthew Piercey

Good point; I guess I've gotten in the habit of adding node-sass, sass-loader, and url-loader/file-loader to my Nuxt projects so much it's second nature.

And core-js@2, up until I started using nuxt-edge...

Collapse
 
dennisk profile image
Dennis Keirsgieter

Using this method does not generate custom-color classes for me.. like has-background-secondary where secondary is my custom color created in Bulma. Any idea how to fix this?

Collapse
 
mtpiercey profile image
Matthew Piercey

I do happen to know that using this method you can't assign a Bulma variable to a custom SCSS variable, only a value, so I probably made a mistake somewhere along the line. Thanks for pointing this out, BTW. Perhaps bulma.io/documentation/customize/w... (or at least the last half of it) could help?

Collapse
 
dennisk profile image
Dennis Keirsgieter

Yeah i now did it by using an extra nuxt module@nuxtjs/style-resources that loads my styles.scss and then if i also load it using the css property in nuxt i get what i want but i do have the feeling its now loading and generating more css then it should since a lot of classes are being there twice. Purgeing my css does not seem to fix that.

Thread Thread
 
mtpiercey profile image
Matthew Piercey

Are you using github.com/Developmint/nuxt-purgecss? Because that's the only way I got PurgeCSS to work. If I'm not mistaken, you otherwise should be doing it right.

Collapse
 
lewiskori profile image
Lewis kori

This is really awesome. nuxt is really heaven-sent. Thanks for sharing. Do you have any resources on persisting vuex data on page refresh?

Collapse
 
mtpiercey profile image
Matthew Piercey

You're in luck - here you go:

// ~/plugins/vuex-persistence.js
// npm install --save vuex-persistedstate or yarn add vuex-persistedstate
import createPersistedState from 'vuex-persistedstate'
/*
  This little plugin is the surprisingly-easy way to make Vuex stuff persist in
  a user's browser's localStorage. Super useful.
*/

export default ({ store, isHMR }) => {
  if (isHMR) { return }

  window.onNuxtReady((nuxt) => {
    createPersistedState()(store)
  })
}

Just import this sucker in nuxt.config.js like so:

plugins: [
'~/plugins/vuex-persistence

]

Collapse
 
lewiskori profile image
Lewis kori

thank you. This worked like a charm. Looking forward to reading more from you!

Collapse
 
maduhaime profile image
Marc-Antoine Duhaime

Can we just use font-awesome as CSS with fonts from the packages?

Collapse
 
mtpiercey profile image
Matthew Piercey

That's totally a legitimate way of doing it; you could even load the CSS from a CDN and import it in nuxt.config.js in the css: option if I'm not mistaken. In fact, it's easier in a lot of ways.

The three main reasons I chose to do it the way I did are:

  • For one reason or another, I like to programmatically load in only the icons I need (even though it isn't easier as such).

  • I've got no scientific proof here, but I'm fairly certain using only the SVG icons you need decreases the bundle size by ~20-30KB

  • I already was using several custom fonts in the project, and I didn't feel like adding another one to the mix.