13th Mar, 2018

Custom checkboxes with collection_check_boxes

DISCLAIMER: This is one of the posts I'm writing to help myself learn new things. This is probably not the best way to do this. If you have a better way, please let me know!

Today, I found myself in a situation where I needed to build some custom checkboxes inside a Rails app. Now, custom checkboxes are not that uncommon when it comes to frontend work, but in my form, I used collection_check_boxes to render a set of checkboxes and I never had to apply custom styles to those.
I'm going to split this up in two parts.

The Markup

Let's say we want our result to look something like this:

![checkboxes example]({{ "assets/images/checkboxes.jpg" | absolute_url }})

The checkbox looks a little like a button, and when checked, it should render a solid background with a white font.
The markup for this looks rather simple:

<label class="custom-checkbox">
  <input type="checkbox" class="checkbox" />
  <span class="custom-label">Label</span>
</label>

The checkbox-hack has been around for a while now, so the following CSS should be no suprise to anybody:

.custom-checkbox
  position: relative

  // Hide default checkbox and move it out of the way
  .checkbox
    position: absolute
    opacity: 0

  .custom-label
    display: inline-block
    padding: 14px 30px
    border: 1px solid grey
    border-radius: 4px
    font-size: 18px
    font-family: sans-serif
    cursor: pointer

  // Apply styles to custom-label when the original checkbox is checked
  .checkbox:checked ~ .custom-label
    color: white
    border-color: #00CBA2
    background-color: #00CBA2

Here, we are using the fact that not only the checkbox itself can be clicked to check or uncheck it, but also the label. We're now hiding the default checkbox and styling the contents of the label (which is just a span in this example) to our likings. When the label is clicked (and thus the checkbox checked), we simply change the styling of the custom label to refelct the state of the checkbox we desire (you can try this out in this simple pen).
From a pure CSS/HTML standpoint, we reached our goal.

The Rails Part

In my from in rails, I was using the following line to render a list of checkboxes for categories:

= f.collection_check_boxes :category_ids, Category.all, :id, :name,
include_hidden: false

There are several ways to get to the markup I described above, but I did not want to forgo the comfort of using collection_check_boxes.
After some searching, I stumbled accros this answer on StackOverflow. Even though it was answering a question about simple_form, I tried to adapt it to my form_for setup.
Here's what I ended up with:

= f.collection_check_boxes :category_ids, Category.all, :id, :name, include_hidden: false do |b|
	= b.label(class: 'custom-checkbox') do
		= b.check_box(class: 'checkbox')
		%span.custom-label= b.text

This way, I could have both: Custom styled checkboxes and the advantages of using collection_check_boxes.

© 2024 Chris Jarling