DEV Community

Drew Bragg
Drew Bragg

Posted on

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.

Top comments (1)

Collapse
 
equivalent profile image
Tomas Valent

also link_to seems to use class_name under the hood

<%= link_to "whatever", #", class: ["flex flex-ycenter", active: true] %>