Rails 6.1 introduces class_names helper
Rails 6.1 introduced the class_names helper to make it easier to add conditional class names to HTML elements. This helper simplifies the common pattern of conditionally applying CSS classes.
Before Rails 6.1
Previously, you had to manually concatenate class names:
<!-- Manual concatenation -->
<div class="<%= 'active' if user.active? %> <%= 'admin' if user.admin? %>">
User content
</div>
<!-- Or using array join -->
<div class="<%= ['active' if user.active?, 'admin' if user.admin?].compact.join(' ') %>">
User content
</div>
This approach was verbose and error-prone.
Rails 6.1 Solution
Rails 6.1 provides the class_names helper:
<div class="<%= class_names('base-class', active: user.active?, admin: user.admin?) %>">
User content
</div>
Basic Usage
Simple Classes
Add classes unconditionally:
<%= class_names('btn', 'btn-primary') %>
<!-- Output: "btn btn-primary" -->
Conditional Classes
Add classes conditionally:
<%= class_names('btn', active: user.active?) %>
<!-- Output: "btn active" if user.active? is true -->
<!-- Output: "btn" if user.active? is false -->
Multiple Conditional Classes
Combine multiple conditions:
<%= class_names(
'btn',
'btn-primary': user.primary?,
'btn-large': user.large?,
'disabled': user.disabled?
) %>
Hash Syntax
Use hash syntax for conditional classes:
<!-- Class name as key, condition as value -->
<%= class_names(
'card',
'active' => post.published?,
'featured' => post.featured?,
'archived' => post.archived?
) %>
Array Syntax
You can also use arrays:
<%= class_names(['btn', 'btn-primary'], 'btn-large': large?) %>
Real-World Examples
Navigation Links
<%= link_to 'Home', root_path, class: class_names(
'nav-link',
'active' => current_page?(root_path)
) %>
Form Fields
<%= form.text_field :email, class: class_names(
'form-control',
'is-invalid' => @user.errors[:email].any?,
'is-valid' => @user.errors[:email].empty? && @user.persisted?
) %>
Cards
<div class="<%= class_names(
'card',
'card-featured' => post.featured?,
'card-published' => post.published?,
"card-#{post.status}"
) %>">
<!-- Card content -->
</div>
Combining with Other Helpers
With content_tag
content_tag :div, class: class_names('container', fluid: fluid?) do
# Content
end
With link_to
<%= link_to 'Profile', user_path(user), class: class_names(
'btn',
'btn-primary' => current_user == user,
'btn-secondary' => current_user != user
) %>
Advanced Usage
Dynamic Class Names
Combine static and dynamic classes:
<%= class_names(
'user',
"user-#{user.role}",
"user-#{user.status}",
'online' => user.online?,
'offline' => !user.online?
) %>
Nested Conditions
Handle complex conditions:
<%= class_names(
'notification',
'unread' => notification.unread?,
'important' => notification.important? && notification.unread?,
'archived' => notification.archived?
) %>
Comparison with Alternatives
Using String Interpolation
<!-- Before: Error-prone -->
<div class="btn <%= 'active' if active? %> <%= 'disabled' if disabled? %>">
<!-- After: Clean and safe -->
<div class="<%= class_names('btn', active: active?, disabled: disabled?) %>">
Using Array Join
<!-- Before: Verbose -->
<div class="<%= ['btn', ('active' if active?), ('disabled' if disabled?)].compact.join(' ') %>">
<!-- After: Concise -->
<div class="<%= class_names('btn', active: active?, disabled: disabled?) %>">
Benefits
The class_names helper provides several advantages:
- Cleaner code: More readable than manual concatenation
- Null safety: Handles nil values gracefully
- Flexibility: Supports multiple syntaxes
- Consistency: Standard way to handle conditional classes
Edge Cases
Nil Values
class_names handles nil gracefully:
class_names('btn', active: nil) # => "btn"
class_names('btn', active: false) # => "btn"
class_names('btn', active: true) # => "btn active"
Empty Strings
Empty strings are ignored:
class_names('btn', '') # => "btn"
class_names('', 'btn') # => "btn"
Best Practices
- Use for conditional classes: Especially useful when you have multiple conditions
- Keep it readable: Don't nest too many conditions
- Combine with helpers: Works well with Rails view helpers
- Use hash syntax: Prefer hash syntax for clarity
Conclusion
Rails 6.1's class_names helper simplifies adding conditional CSS classes to HTML elements. It provides a clean, readable way to handle complex class name logic, making your views more maintainable and less error-prone.