How to Conditionally Apply a CSS Class in Vue.js

    Chad Campbell
    Share

    There are times you need to change an element’s CSS classes at runtime. But when changing classes, it’s sometimes best to apply style details conditionally. For example, imagine your view has a pager. Pagers are often used to navigate larger sets of items. When navigating, it can be helpful to show the user the page they’re currently on. The style of the item is conditionally set, based on the current page that’s being viewed.

    A pager in this case may look something like this:

    Pager

    In this example, there are five pages. Only one of these pages is selected at a time. If you built this pager with Bootstrap, the selected page would have a CSS class named active applied. You’d want this class applied only if the page was the currently viewed page. In other words, you’d want to conditionally apply the active CSS class. Luckily, Vue provides a way to conditionally apply a CSS class to an element, which I’m going to demonstrate in this article.

    To conditionally apply a CSS class at runtime, you can bind to a JavaScript object. To successfully complete this task, you must complete two steps. First, you must ensure that your CSS class is defined. Then, you create the class bindings in your template. I’m going to explain each of these steps in detail in the rest of this article.

    Jump Start Vue

    Step 1: Define Your CSS Classes

    Imagine, for a moment, that the five page items shown in the image above were defined using the following HTML:

    <div id="myApp">
      <nav aria-label="Page navigation example">
        <ul class="pagination">
          <li class="page-item"><a class="page-link" href="#">1</a></li>
          <li class="page-item"><a class="page-link" href="#">2</a></li>
          <li class="page-item active"><a class="page-link" href="#">3</a></li>
          <li class="page-item"><a class="page-link" href="#">4</a></li>
          <li class="page-item"><a class="page-link" href="#">5</a></li>
        </ul>
      </nav>
    </div>
    

    Notice that each page in this code snippet has a list-item element (<li …). That element references the page-item CSS class. In the code for this article, this class is defined in the Bootstrap CSS framework. However, if it weren’t defined there, it would be your responsibility to ensure that it was defined somewhere. The second CSS class is the one that’s most relevant to this article, though.

    The active CSS class is used to identify the currently selected page. For this article, this CSS class is also defined in the Bootstrap CSS. As shown in the snippet above, the active class is only used in the third list item element. As you can probably guess, this is the CSS class that you want to apply conditionally. To do that, you need to add a JavaScript object.

    Step 2: Create Your Class Bindings

    Let’s build on the code snippet shown in step 1. When creating class bindings in your template, there are two primary choices: using the object syntax or using the array syntax. I’m going to show you how to use both approaches in the remainder of this article.

    Binding using object syntax

    To create a class binding using the object syntax, you have to use a JavaScript expression. The expression we’ll be using can be seen in the code associated with this article here. That relevant code looks like this:

    <div id="myApp">
      <nav aria-label="An example with pagination">
        <ul class="pagination">
          <li v-for="page in totalPages" v-bind:class="{'page-item':true, 'active':(page === currentPage)}">
            <a class="page-link" href="#">{{ page }}</a>
          </li>
        </ul>
      </nav>
    </div>
    

    I’ve reduced the amount of code by using Vue’s baked-in v-for directive. This directive is used to render items in a loop. The items in this example are the pages themselves. Beyond the use of the v-for directive, notice the use of the v-bind directive.

    The v-bind directive connects the element’s class attribute to the Vue instance. That instance of Vue is defined like this:

    var app = new Vue({
      el: '#myApp',
      data: {
        totalPages: 5,
        currentPage: 3
      }
    });
    

    This Vue instance is straight to the point. The data object above includes a property named currentPage. If you revisit the HTML template defined above, you’ll notice that this property is being referenced. In fact, the JavaScript object associated with each class binding looks something like this:

    {'page-item':true, 'active':(page === currentPage)}
    

    This object defines two properties: page-item and active. Notably, these are the names of the two CSS classes discussed in Step 1. In Step 2, these two class references have become property names in a JavaScript object. The values associated with these property names are JavaScript expressions. If the expression evaluates as truthy, the CSS class will be included. If the expression evaluates to false, the CSS class will not be included. With these rules in mind, let’s look at each property.

    The first property, page-item, has a value of true. This hard-coded value is used because we always want to include the page-item class. The second property, active, uses a JavaScript expression. When this expression is true, the active class will be applied. This empowers us to conditionally apply the active class based on the value of currentPage. Another way to conditionally apply the active class is by binding to an Array.

    Binding using array syntax

    Vue lets you apply a list of CSS classes by binding to an Array. If you wanted to use the Array syntax, the HTML shown in Step 1 would become this:

    <div id="myApp">
      <nav aria-label="An example with pagination">
        <ul class="pagination">
            <li v-for="page in totalPages" v-bind:class="[pageItemClass, (page === currentPage) ? activeClass : '']">
              <a class="page-link" href="#">{{ page }}</a>
            </li>
        </ul>
      </nav>
    </div>
    

    A running version with the Array syntax can be seen here. The only difference is the use of an Array on the class binding. This alternative approach expects two additional properties to exist in your Vue’s data object. Those two properties are: pageItemClass and activeClass. The updated Vue initialization code with these properties looks like this:

    var app = new Vue({
      el: '#myApp',
      data: {
        totalPages: 5,
        currentPage: 3,
        pageItemClass: 'page-item',
        activeClass: 'active'
      }
    });
    

    As you can see, the data object has grown in size, but the code in the template is slightly cleaner when using the Array syntax. The object syntax is a little bit more compact. The choice between the object syntax and the Array syntax comes down to personal preference.

    Both approaches may seem to make your HTML template more complicated. However, there’s actually more going on here. In reality, we’re separating concerns. We’re creating a template that is driven by data. This makes the view easier to test and easier to maintain as the app grows.

    Wrap Up

    I hope you found this article valuable. If you’d like to learn more about Vue.js, why not check out some of our other Vue content here on SitePoint. Otherwise, you can find me on Twitter @chadcampbell. Once again, thank you!