Introducing the Rails class_names method

drbragg

Drew Bragg

Posted on March 22, 2021

Introducing the Rails class_names method

New to Rails 6.1 is a method called class_names, from the ActionView::Helpers::TagHelper module. This handy new view helper brings one of may favorite features from Vue.js to Rails.

In Vue.js (or React via the classnames library) we can do something like this:

<div class="{item: true, item__complete: item.complete, item__over_due: !item.complete && item.overDue }">
  {{ item.name }}
</div>
Enter fullscreen mode Exit fullscreen mode

Which, assuming we have the proper css classes and item object, will give us something like this:

<!-- item.complete == false -->
<div class="item">Incomplete Item</div>

<!-- item.complete == false && item.overDue == true -->
<div class="item item__over_due">Incomplete Item</div>

<!-- item.complete == true && item.overDue == true -->
<div class="item item__complete">Complete Item</div>
Enter fullscreen mode Exit fullscreen mode

Obviously this is an overly simplified example but you get the idea. To do the same thing in Rails used to require something like this:

<%= tag.div class: "item #{item.completed? ? 'item__complete' : ''} #{!item.completed? && item.over_due? ? 'item__over_due' : ''}" do %>
  <%= item.name %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

However, the introduction of class_names simplifies this and makes it work very similarly to Vue. Now we can do something like this:

<%= tag.div class: class_names(item: true, item__complete: item.completed?, item__over_due: !item.completed? && item.over_due?) do %>
  <%= item.name %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

Additionally, class_names can take mixed argument types so the above could also be done as:

<%= tag.div class: class_names("item", { item__complete: item.completed?, item__over_due: !item.completed? && item.over_due? }) do %>
  <%= item.name %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

NOTE: The above example explicitly calls class_names for illustrative purposes. The tag (and content_tag) method uses class_names under the hood already so the above can actually be done like this:

<%= tag.div class: ["item", { item__complete: item.completed?, item__over_due: !item.completed? && item.over_due? }] do %>
  <%= item.name %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

I like this a lot and it will make building more complex conditional css class lists in Rails so much easier and cleaner. class_names is an alias of token list and you can view its documentation here.

💖 💪 🙅 🚩
drbragg
Drew Bragg

Posted on March 22, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related