Checkbox

Versatile checkbox component for single selections, collections, and toggle switches.

Key Features

  • 5 Variants - Checkbox, Switch, Card, Pill, Button
  • Icon Support - Add icons with with_icon slot
  • Single & Collections - Single checkbox or multiple from arrays/ActiveRecord
  • Select All - Built-in select all with indeterminate state
  • Smart Labels - Auto-derives label from model attribute name in form mode
  • Unique IDs - Includes record ID for safe use in lists and repeated forms
  • Auto-Submit - CSP-safe form submission on change via Stimulus
  • Input HTML - Pass attributes directly to the <input> element
  • Strikethrough - Line-through + muted color on check for todo/task lists
  • Label Class - Custom CSS classes on the label element
  • Form Builder - Full Rails form integration (f.rui_checkbox)
  • 5 Sizes - xs, sm, base, lg, xl
  • 2 Shapes - Square or rounded corners
  • All Colors - Semantic + any Tailwind color
  • Full Accessibility - ARIA attributes, keyboard navigation
  • JavaScript API - Programmatic control with data-action attributes

Basic Usage

Simple checkbox with label and optional help text. Use the positional first argument for clean, Rails-like syntax.

Basic Usage
<%= rui_checkbox(:terms_accepted, label: "I accept the terms and conditions") %>

<%= rui_checkbox(:newsletter,
  label: "Subscribe to newsletter",
  help_text: "We'll send you weekly updates"
) %>

We'll send you weekly updates

Colors

Supports all Tailwind colors via ColorBuilderHelper - semantic colors plus any Tailwind color.

Semantic Colors

Semantic Colors
<%= rui_checkbox(object: :demo, method: :opt1, label: "Primary", color: :primary, checked: true) %>
<%= rui_checkbox(object: :demo, method: :opt2, label: "Success", color: :success, checked: true) %>
<%= rui_checkbox(object: :demo, method: :opt3, label: "Warning", color: :warning, checked: true) %>
<%= rui_checkbox(object: :demo, method: :opt4, label: "Danger", color: :danger, checked: true) %>

Tailwind Colors

Use any Tailwind color directly - indigo, pink, violet, teal, and more!

Tailwind Colors
<%= rui_checkbox(object: :demo, method: :opt1, label: "Indigo", color: :indigo, checked: true) %>
<%= rui_checkbox(object: :demo, method: :opt2, label: "Pink", color: :pink, checked: true) %>
<%= rui_checkbox(object: :demo, method: :opt3, label: "Violet", color: :violet, checked: true) %>
<%= rui_checkbox(object: :demo, method: :opt4, label: "Teal", color: :teal, checked: true) %>

Tip: Colors are generated dynamically using ColorBuilderHelper. This ensures consistency across all components and supports any color from the Tailwind palette.

Sizes

Five size options from extra small to extra large.

Sizes
<%= rui_checkbox(object: :demo, method: :xs, label: "Extra Small", size: :xs, checked: true) %>
<%= rui_checkbox(object: :demo, method: :sm, label: "Small", size: :sm, checked: true) %>
<%= rui_checkbox(object: :demo, method: :base, label: "Base (default)", size: :base, checked: true) %>
<%= rui_checkbox(object: :demo, method: :lg, label: "Large", size: :lg, checked: true) %>
<%= rui_checkbox(object: :demo, method: :xl, label: "Extra Large", size: :xl, checked: true) %>

Shapes

Square or rounded corner styles for checkbox inputs.

Shapes
<%= rui_checkbox(object: :demo, method: :rounded, label: "Rounded (default)", shape: :rounded) %>
<%= rui_checkbox(object: :demo, method: :square, label: "Square", shape: :square) %>

Note: The shape option only applies to the checkbox variant. Switch variant is always fully rounded.

Switch Variant

Toggle switch style for on/off settings.

Switch Variant
<%= rui_checkbox(
  object: :settings,
  method: :dark_mode,
  label: "Enable Dark Mode",
  variant: :switch,
  color: :primary
) %>

<%= rui_checkbox(
  object: :settings,
  method: :notifications,
  label: "Push Notifications",
  variant: :switch,
  color: :success,
  checked: true
) %>

Switch Sizes

Card Variant

Bordered cards with full-width click targets. Perfect for feature selection, pricing plans, or subscription preferences.

Card Variant
<%= rui_checkbox(
  object: :subscription,
  method: :newsletter,
  label: "Newsletter",
  description: "Get the latest updates and offers.",
  variant: :card,
  color: :primary,
  checked: true
) do |cb|
  cb.with_icon(:newspaper)
end %>

Subscription Preferences

Simple Cards (Without Icons)

Card Sizes

Pill Variant

Compact, tag-like selections. Perfect for filters, categories, or tags.

Pill Variant
<div class="flex flex-wrap gap-2">
  <%= rui_checkbox(variant: :pill, label: "Ruby", color: :red, checked: true) %>
  <%= rui_checkbox(variant: :pill, label: "Rails", color: :rose) %>
  <%= rui_checkbox(variant: :pill, label: "JavaScript", color: :yellow) %>
  <%= rui_checkbox(variant: :pill, label: "TypeScript", color: :blue) %>
</div>

Pill Sizes

Button Variant

Toolbar-style toggle controls. Perfect for feature toggles, formatting toolbars, or option selection.

Button Variant
<%= rui_checkbox(variant: :button, label: "Notifications", color: :zinc) do |cb|
  cb.with_icon(:bell)
end %>

Features

Text Formatting Toolbar

View Toggle Buttons

Button Colors

Collections

Render multiple checkboxes from an array or ActiveRecord collection.

Collections
<%= rui_checkbox(
  object: @user,
  method: :category_ids,
  collection: Category.all,
  label: "Select Categories",
  help_text: "Choose one or more categories"
) %>

<%= rui_checkbox(
  object: @user,
  method: :role_ids,
  collection: Role.all,
  value_method: :id,
  text_method: :name,
  label: "Assign Roles"
) %>
Select Categories

Choose one or more categories

Horizontal Layout

Horizontal Layout
<%= rui_checkbox(
  object: @user,
  method: :interests,
  collection: Interest.all,
  layout: :horizontal,
  label: "Select Interests"
) %>
Select Interests

Select All

Enable a "Select All" checkbox for collections with automatic indeterminate state.

Select All
<%= rui_checkbox(
  object: @user,
  method: :permission_ids,
  collection: Permission.all,
  select_all: true,
  label: "Assign Permissions"
) %>
Assign Permissions

Click 'Select All' or choose individual permissions

Indeterminate State: When some (but not all) items are checked, the "Select All" checkbox shows an indeterminate state (a dash instead of checkmark).

Descriptions

Add descriptions to individual checkboxes or collection items.

Descriptions
<%= rui_checkbox(
  object: :user,
  method: :marketing,
  label: "Marketing Emails",
  description: "Receive promotional offers and product updates"
) %>

<%= rui_checkbox(
  object: @user,
  method: :plan_id,
  collection: Plan.all,
  text_method: :name,
  description_method: :description,
  label: "Select Plan"
) %>

Receive promotional offers and product updates

Get notified about account security events

States

Disabled and required states for checkboxes.

States
<%= rui_checkbox(object: :user, method: :locked, label: "Locked option", disabled: true) %>
<%= rui_checkbox(object: :user, method: :terms, label: "I agree to terms", required: true) %>

Smart Labels

In form mode, the checkbox automatically derives a label from the model attribute name when no explicit label is provided.

Smart Labels
<%= form_with model: @user do |f| %>
  <%= f.rui_checkbox(:terms_accepted) %>

  <%= f.rui_checkbox(:terms_accepted, label: "I agree to the Terms of Service") %>

  <%= f.rui_checkbox(:featured, label: false) %>
<% end %>

Label resolution priority: Explicit label → label: false (suppresses) → human_attribute_name (ActiveRecord) → humanize (fallback) → "Checkbox" (standalone default).

Unique IDs

When the checkbox is bound to a persisted object (one with an id), the record ID is included in the generated id and for attributes. This prevents ID collisions when rendering multiple checkboxes for different records on the same page.

Unique IDs
<%= form_with model: @user do |f| %>
  <%= f.rui_checkbox(:completed, label: "Done") %>
<% end %>

<%= form_with model: @user do |f| %>
  <%= f.rui_checkbox(:category_ids, collection: Category.all) %>
<% end %>
Mode Generated ID
Form with persisted object (id: 42) user_42_completed
Form with new object (no id) user_completed
Collection item (id: 42, value: 1) user_42_category_ids_1
Standalone terms

Strikethrough

Enable strikethrough: true to add a line-through and muted color to the label when checked. Perfect for todo lists, task trackers, and shopping lists.

Strikethrough
<%= rui_checkbox(object: :todo, method: :completed,
  label: "Buy groceries",
  strikethrough: true,
  checked: true
) %>

<%= rui_checkbox(object: :todo, method: :laundry,
  label: "Do laundry",
  strikethrough: true
) %>

How it works: Uses pure CSS group-has-[:checked] — when the checkbox inside the .group wrapper is checked, the label gets line-through and a muted color. The color change is animated with transition-all duration-300. No JavaScript required.

Label Class

Use label_class: to append custom CSS classes to the label element. Works alongside all other label features.

Label Class
<%= rui_checkbox(object: :demo, method: :custom,
  label: "Custom styled label",
  label_class: "text-lg italic"
) %>

<%= rui_checkbox(object: :todo, method: :task,
  label: "Important task",
  strikethrough: true,
  label_class: "font-bold"
) %>

Auto-Submit

Enable auto_submit: true to automatically submit the parent form when the checkbox changes. Uses a CSP-safe Stimulus data-action instead of inline JavaScript.

Auto-Submit
<%= form_with model: @todo, url: todo_path(@todo), method: :patch do |f| %>
  <%= f.rui_checkbox(:completed, auto_submit: true) %>
<% end %>

<%= form_with model: @settings do |f| %>
  <%= f.rui_checkbox(:notifications, variant: :switch, auto_submit: true) %>
<% end %>

How it works: Adds data-controller="checkbox" to the wrapper and data-action="change->checkbox#submitForm" to the input. The Stimulus controller calls form.requestSubmit() on the closest parent form. If no form exists, it does nothing gracefully.

Input HTML

Pass attributes directly to the underlying <input> element using the input_html option. Useful for adding custom data attributes, Stimulus actions, or CSS classes to the input itself (not the wrapper).

input_html
<%= rui_checkbox(:terms, label: "I agree",
  input_html: { data: { turbo: false } }
) %>

<%= f.rui_checkbox(:completed,
  auto_submit: true,
  input_html: { data: { action: "change->analytics#track" } }
) %>

<%= rui_checkbox(:dark_mode, label: "Dark Mode",
  input_html: { class: "custom-toggle" }
) %>

Merge behavior: data-action and data-controller values are space-concatenated with internal Stimulus values (not overwritten). class is appended. All other attributes overwrite.

Rails-Compatible API

rui_checkbox accepts standard Rails positional argument patterns for collection checkboxes in addition to the keyword API.

Positional Choices
<!-- Simple array -->
<%= f.rui_checkbox(:category_ids, ["Tech", "Design", "Business"]) %>

<!-- Array of [text, value] pairs -->
<%= f.rui_checkbox(:category_ids, [["Tech", 1], ["Design", 2], ["Business", 3]]) %>
collection_select Style
<!-- ActiveRecord collection with value and text methods -->
<%= f.rui_checkbox(:category_ids, Category.all, :id, :name) %>

<!-- With additional options -->
<%= f.rui_checkbox(:category_ids, Category.all, :id, :name, label: "Categories") %>
Standalone with Positional Args
<%= rui_checkbox(:category_ids, Category.all, :id, :name, label: "Categories") %>

Priority rule: When both positional choices and the collection: keyword are provided, the collection: keyword always wins. Single checkboxes (no collection) are unaffected.

Form Builder Integration

Use with Rails form builder for automatic object binding and validation.

Form Builder
<%= form_with model: @user do |f| %>
  <%= f.rui_checkbox(:terms_accepted) %>

  <%= f.rui_checkbox(:newsletter, label: "Subscribe to updates", color: :primary) %>

  <%= f.rui_checkbox(:completed, auto_submit: true) %>

  <%= f.submit "Sign Up" %>
<% end %>

Note: When using f.rui_checkbox, the checked state is automatically detected from the form object, labels are derived from the model attribute name, and IDs include the record ID for uniqueness.

Rails Integration

rui_checkbox provides a styled alternative to Rails ActionView checkbox helpers with additional features like variants, colors, and collections with select all.

Comparison with Rails Helpers

Here's how rui_checkbox compares to standard Rails helpers:

Rails Helper rui_checkbox Equivalent
f.check_box f.rui_checkbox(:method)
check_box(:obj, :method) rui_checkbox(object: :obj, method: :method)
check_box_tag(:name) rui_checkbox(name: :name)
f.collection_check_boxes f.rui_checkbox(:method, collection: items)

Single Boolean Field

For boolean attributes on a model:

Single Boolean Field
<%= f.rui_checkbox(:featured,
  label: "Featured Post",
  description: "Display prominently on homepage",
  color: :primary
) %>

Collection Checkboxes

For has_many associations or array selections:

Collection Checkboxes
<%= f.rui_checkbox(:category_ids,
  collection: Category.all,
  value_method: :id,
  text_method: :name,
  select_all: true,
  label: "Categories",
  color: :primary
) %>

Real-World Example: Post Form

See the checkbox component in action on the New Post and Posts pages.

Real-World Example: Post Form
<%= form_with model: @post do |f| %>
  <%= f.rui_checkbox(:featured,
    description: "Display this post prominently",
    color: :primary
  ) %>

  <%= f.rui_checkbox(:notify_subscribers,
    variant: :switch,
    color: :success,
    auto_submit: true
  ) %>

  <%= f.rui_checkbox(:allow_comments,
    help_text: "Visitors can comment on this post",
    color: :info
  ) %>

  <%= f.rui_button(color: :success) %>
<% end %>

Pro Tip: rui_checkbox automatically generates the hidden field that Rails uses for unchecked checkboxes, ensuring proper form submission with boolean values.

Accessibility

The Checkbox component follows WAI-ARIA best practices for form controls.

ARIA Attributes

  • Help text linked via aria-describedby for context
  • Required fields include aria-required="true"
  • Error states include aria-invalid="true"
  • Checkbox groups use role="group" with aria-labelledby

Keyboard Navigation

  • Tab moves focus between checkboxes
  • Space toggles the checkbox state
  • Focus states are clearly visible with ring styles

Semantic HTML

  • Uses native <input type="checkbox"> elements
  • Labels use for attribute linked to input id (unique per record)
  • Indeterminate state properly communicates partial selection via indeterminate property
  • Auto-submit uses CSP-safe Stimulus data-action instead of inline JavaScript

Screen Reader Support

  • Checkbox state is announced as "checked", "not checked", or "mixed" (indeterminate)
  • Error messages are announced when validation fails
  • Help text provides additional context when focused

JavaScript API

The Checkbox component provides two Stimulus controllers for interactive features.

Checkbox Controller

Handles Select All functionality, indeterminate state, and auto-submit:

Action Description
checkbox#toggleAll Toggles all item checkboxes based on select-all state
checkbox#updateSelectAll Updates select-all checkbox state (checked/indeterminate/unchecked)
checkbox#submitForm Submits the closest parent form (used by auto_submit: true). Does nothing if no form exists.
Select All Pattern
<div data-controller="checkbox">
  <input type="checkbox"
         data-checkbox-target="selectAll"
         data-action="change->checkbox#toggleAll">
  <label>Select All</label>

  <input type="checkbox"
         data-checkbox-target="item"
         data-action="change->checkbox#updateSelectAll">
  <input type="checkbox"
         data-checkbox-target="item"
         data-action="change->checkbox#updateSelectAll">
</div>

Checkbox Switch Controller

Handles the switch/toggle visual animation:

Action Description
checkbox-switch#updateThumbPosition Updates thumb position based on checked state

Programmatic Control

Control checkboxes from JavaScript:

Programmatic Control
// Get the checkbox controller (for select-all functionality)
const container = document.querySelector('[data-controller="checkbox"]')
const checkboxController = application.getControllerForElementAndIdentifier(
  container,
  "checkbox"
)

// Update select-all state after programmatic changes
checkboxController.updateSelectAllState()

// Toggle all items programmatically
const selectAll = container.querySelector('[data-checkbox-target="selectAll"]')
selectAll.checked = true
selectAll.dispatchEvent(new Event("change"))

API Reference

rui_checkbox

Versatile checkbox with 5 variants (checkbox, switch, card, pill, button), collections, select all, smart labels, unique IDs, and auto-submit

Parameter Type Default Description
name_or_method Symbol/String Positional first arg - name for standalone, method for form builder
label String/false Label text for single checkbox or legend for collection. Pass false to suppress label.
description String Description text displayed below label
help_text String Help text displayed below checkbox/group

Appearance

Visual styling options

Parameter Type Default Description
variant Symbol :checkbox Visual variant style
:checkbox :switch :card :pill :button
color Symbol :primary Checked state color - semantic or any Tailwind color
size Symbol :base Checkbox size
:xs :sm :base :lg :xl
shape Symbol :rounded Corner style (checkbox variant only)
:square :rounded
layout Symbol :vertical Layout for collections
:vertical :horizontal

States

Checkbox state options

Parameter Type Default Description
checked Boolean Explicit checked state (overrides object value)
disabled Boolean false Disable the checkbox
required Boolean false Show required indicator (*)

Behavior

Interactive behavior options

Parameter Type Default Description
auto_submit Boolean false Auto-submit the parent form when checkbox changes (CSP-safe via Stimulus)
strikethrough Boolean false Adds line-through + muted color to label when checked. Pure CSS via group-has-[:checked]. Checkbox variant only.
label_class String Custom CSS classes appended to the label element
input_html Hash {} Additional HTML attributes passed directly to the <input> element. Stimulus data-action and data-controller values are space-concatenated with internal ones.

Values

Checked/unchecked value configuration

Parameter Type Default Description
value String "1" Value when checkbox is checked
unchecked_value String "0" Value sent when unchecked (hidden field)

Collections

Options for rendering multiple checkboxes from a collection

Parameter Type Default Description
collection Array/ActiveRecord Collection for multiple checkboxes
value_method Symbol :id Method to get value from collection items
text_method Symbol :name Method to get label text from collection items
description_method Symbol Method to get description from collection items
select_all Boolean false Show 'Select All' checkbox with indeterminate state

Form Builder

Options when used with Rails form builder (f.rui_checkbox)

Parameter Type Default Description
form FormBuilder Rails form builder instance (auto-set by f.rui_checkbox)
object Object/Symbol Object to bind checkbox to
method Symbol Attribute name on the object (keyword alternative to positional)
name String Input name attribute (keyword alternative to positional)

Slots

Content slots for customizing component parts

Slot Description
icon Icon slot for button/pill/card variants via checkbox.with_icon(:name)

JavaScript & Namespacing

Checkbox ships a Stimulus controller registered under the identifier checkbox. If you set config.stimulus_namespace = "rui" ( see guide ), every emitted Stimulus attribute is prefixed: the identifier becomes rui--checkbox.

💡 Working with your own Stimulus controllers? Read Stimulus Namespace to keep the gem's controllers from colliding with yours.

JS registration (app/javascript/controllers/index.js)

Without namespace
import CheckboxController from "./rapid_rails_ui/checkbox_controller"
application.register("checkbox", CheckboxController)
With config.stimulus_namespace = "rui"
import CheckboxController from "./rapid_rails_ui/checkbox_controller"
application.register("rui--checkbox", CheckboxController)

Custom trigger button

Without namespace
<button data-action="checkbox#open">Trigger</button>
With namespace (either form works)
<button data-action="rui--checkbox#open">Trigger</button>

<button data-action="<%= stimulus_action("<%= controller_id %>", "click->#open") %>">Trigger</button>

Related Components