Organizing Component CSS Styles and Integrating Font Awesome Unicode Icons in Vue
In this lesson, we're going to reorganize our styles so that they are scoped appropriately, so we need to sort through the different styles being called in our application and move them so that they are in their proper places.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

We're going to just go down the line, literally class by class and pick out which ones need to go in which spots, and then we're going to move them over. Now, this guide may seem a little bit tedious but it is something that is important to do.

At the end of the guide, we'll just make sure that everything looks exactly like how we have it now. I think we did a good job in the front end course on naming these appropriately so that now it's pretty straightforward to see exactly which ones are unique.

Homepage.vue

<style scoped>
@import "https://use.fontawesome.com/releases/v5.0.13/css/all.css";
.container-homepage {
  margin-top: 5em;
  align-items: center;
  height: 100vh;
}
.homepage-logo {
  grid-column: 2;
  grid-row: 1;
}
.homepage-logo img {
  width: 10.5rem;
}
.homepage-search-bar input {
  height: 11.8rem;
}
.recent-posts-wrapper {
  grid-column: 1/-1;
  grid-row: 3;
}
.recent-posts-heading {
  color: #2660f3;
  margin-bottom: 3rem;
  font-size: 1.4rem;
}
.recent-posts {
  display: grid;
  width: 66vw;
  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
  grid-gap: 2.5rem;
}
.recent-post-title a {
  color: #535353;
  font-size: 1.4rem;
  text-decoration: none;
}
.recent-post-category {
  color: #999999;
  font-size: 1.2rem;
  font-weight: 600;
}
</style>

Now for SearchResults.vue

SearchResults.vue

<style scoped>
.container-results {
  margin-top: 2em;
}
.results-search-bar input {
  height: 5rem;
  margin-bottom: 1em;
  margin-top: 3em;
}
.results-posts-wrapper {
  grid-row: 3;
  grid-column: 1/-1;
  width: 66vw;
}
.post {
  margin-top: 3em;
  margin-bottom: 3em;
}
.category-name {
  color: #2660f3;
  margin-bottom: 1.5rem;
  font-size: 1.4rem;
  font-weight: 600;
}
.category-name span {
  margin-right: 15px;
}
.result-post-title a {
  color: #535353;
  text-decoration: none;
  font-size: 1.8rem;
}
.result-post-links-wrapper {
  margin-top: 2rem;
  display: grid;
  grid-template-columns: repeat(auto-fit, 1fr);
  grid-gap: 2rem;
}
.result-post-link {
  color: #535353;
  text-decoration: none;
  font-size: 1.4rem;
}
.result-post-link:hover {
  text-decoration: underline;
}
.results-logo {
  grid-row: 1;
  grid-column: 2;
  display: flex;
  justify-content: center;
  align-items: center;
}
.results-logo img {
  width: 50px;
}
</style>

Now, if you are using Vue and you're using the scoped styles, then technically you don't even need to have names like homepage because everything is only going to be applied directly into that component.

However, I personally like having the name here just because if I ever were to build this out or convert this Vue app into a React app or an Angular app, or something like that, then I would definitely not enjoy having to add in all of these names.

I will leave up to you and your own preferences. Now, we don't want our app to get just completely bloated and technically when you start to get to an even bigger project, then you're just going to create a dedicated styles directory, but with an app this size it's really not necessary.

Okay, now that all of those are moved over, let's open up the browser and check to see if everything still works.

large

It looks like all of our styles have remained intact, so we were able to do that in about five minutes. Now that we have that finished, let's also knock out Font Awesome.

With Font Awesome, there are a couple different ways of bringing it in, as great as it is, is really a pain to integrate with Vue if you want to go with a full integration. If you want to bring it in, the recommended approach is to use it on a component basis.

That means that for every icon you'd implement, you would create a dedicated component for that icon and then bring it in, which is the way that I do it in most applications. The problem is in this app we don't actually want the full icon in an HTML kind of component.

We actually just want to get access to the Unicode here and that is something that is much more challenging to do on a component basis.

If you remember, whenever you get a component, a component is going to return HTML, so you have to put it in some kind of HTML wrapper and that's what gets placed. You can't just return a Unicode element without doing a ton of very frustrating parsing.

We're not going to do any of that. We're actually just going to cheat a little bit here, and when I say cheat, I mean we're going to do it the easiest way humanly possible.

What I'm going to do is I'm going to head to the 'Get Started' on their website and I'm just going to grab this href here I'm going to just copy it.

href="https://use.fontawesome.com/releases/v5.0.13/css/all.css"

This is the version of Font Awesome used in the video, it has since been updated.

Now let's open up Homepage.vue and inside of the style tag, you can use import statements. Traditionally you do it inside of SASS files, but you're able to also do that inside of your style component here.

large

And now that it's imported, what I'm going to do is put it inside of a data element.

Homepage.vue

<script>
export default {
  name: "Homepage",
  data() {
    return {
      recentPosts: [],
      searchPlaceholder: `\uf002 Search DailySmarty`
    };
  },
}
</script>

Now we have access to this data up here. I'm now going to make it a bound directive.

Homepage.vue

<div class="search-bar homepage-search-bar">
    <input type="text" :placeholder="searchPlaceholder" @keyup.enter="submitQuery">
    <p>Press return to search</p>
</div>

large

You can see that we have our icon. That is working perfectly and it is a much easier implementation then building out our own component, parsing and doing all kinds of things like that. I think this is a more straightforward approach.

Let's copy all of that and let's place it inside of our SearchResults.vue, then add in the import.

large

Then we add it into the data element.

SearchResults.vue

<script>
export default {
  name: "SearchResults",
  data() {
    return {
      query: null,
      results: [],
      searchPlaceholder: `\uf002 Search DailySmarty`
    };
  },
}
</script>

Now let's add it into the HTML.

SearchResults.vue

<div class="search-bar results-search-bar">
    <input type="text" :placeholder="searchPlaceholder" @keyup.enter="submitQuery">
</div>

Now we come back to the search results page you can see that that is pulling it in properly.

large

I'm really happy with the fact that now our styles are organized, and finally, our icon is there and is looking good.

In the next guide, we're going to finish up some of the final tasks that I want to integrate, and that really revolves around some behavior and some user experience items here on the search results page.

We're also going to add in some data validation and some improvements on the UX, such as adding some text for what happens when a user searches for data that are for a query that doesn't exist, or if they type in a duplicate query, all kinds of different edge cases. We'll take care of that in the next guide.

Resources