rails_bootstrap_form

Rails form helpers and form builder extensions that make it super easy to build Bootstrap 5 forms.


Keywords
bootstrap5, date-helpers, form-builder, form-helpers, form-options-helpers, form-validation, rails, ruby
License
MIT
Install
gem install rails_bootstrap_form -v 0.9.9

Documentation

RailsBootstrapForm

Ruby Gem Version Gem Downloads Test Coverage Maintainability

rails_bootstrap_form is a Rails form builder that makes it super easy to integrate Bootstrap 5 forms into your Rails application. rails_bootstrap_form's form helpers generate the form field and its label along with all the Bootstrap mark-up required for proper Bootstrap display.

Minimum Requirements

Installation

Install Bootstrap 5. There are many ways to do this, depending on the asset pipeline you're using in your Rails application. One way is to use the gem that works with Sprockets. To do so, in a brand new Rails 7.0 application created without the --webpacker option, add the bootstrap gem to your Gemfile:

gem "bootstrap", "~> 5.0"

And follow the remaining instructions in the official bootstrap installation guide for setting up application.scss and application.js.

Add the rails_bootstrap_form gem to your Gemfile:

gem "rails_bootstrap_form", "~> 0.9.8"

Then:

bundle install

Depending on which CSS pre-processor you are using, adding the bootstrap form styles differs slightly. If you use Rails in the default mode without any pre-processor, you'll have to add the following line to your application.css file:

*= require rails_bootstrap_form

If you followed the official bootstrap installation guide, you'll probably have switched to SCSS. In this case add the following line to your application.scss:

@import "rails_bootstrap_form";

Configuration

rails_bootstrap_form can be used without any configuration. However, rails_bootstrap_form does have an optional configuration file at config/initializers/rails_bootstrap_form.rb for setting options that affect all generated forms in an application. This configuration file is created using the generator by running the command:

$ rails generate rails_bootstrap_form:install

Example:

# config/initializers/rails_bootstrap_form.rb
RailsBootstrapForm.configure do |config|
  # to make forms non-compliant with W3C.
  config.default_form_attributes = {novalidate: true}
end

The current configuration options are:

Option Default value Description
default_form_attributes Set this option to {novalidate: true} to instruct rails_bootstrap_form to skip all HTML 5 validation.

Usage

bootstrap_form_for

To get started, use the bootstrap_form_for helper in place of the Rails form_for helper. Here's an example:

bootstrap_form_for

<%= bootstrap_form_for(@user) do |f| %>
  <%= f.email_field :email %>
  <%= f.password_field :password %>
  <%= f.check_box :remember_me %>
  <%= f.primary "Log In" %>
<% end %>

This generates the following HTML:

<form novalidate="novalidate" class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
  <div class="mb-3">
    <label class="form-label required" for="user_email">Email address</label>
    <input class="form-control" aria-required="true" required="required" type="email" name="user[email]" id="user_email">
  </div>
  <div class="mb-3">
    <label class="form-label required" for="user_password">Password</label>
    <input class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
  </div>
  <div class="mb-3">
    <div class="form-check">
      <input class="form-check-input" type="checkbox" value="1" name="user[terms]" id="user_terms">
      <label class="form-check-label" for="user_terms">I accept terms and conditions</label>
      <div class="form-text text-muted">You must first accept terms and conditions in order to continue</div>
    </div>
  </div>
  <input type="submit" name="commit" value="Log In" class="btn btn-primary" data-disable-with="Log In">
</form>

bootstrap_form_with

To get started, use the bootstrap_form_with helper in place of the Rails form_with helper. Here's an example:

bootstrap_form_with

<%= bootstrap_form_with(model: @user) do |f| %>
  <%= f.email_field :email %>
  <%= f.password_field :password %>
  <%= f.check_box :remember_me %>
  <%= f.primary "Log In" %>
<% end %>

This generates the following HTML:

<form novalidate="novalidate" class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
  <div class="mb-3">
    <label class="form-label required" for="user_email">Email address</label>
    <input class="form-control" aria-required="true" required="required" type="email" name="user[email]" id="user_email">
  </div>
  <div class="mb-3">
    <label class="form-label required" for="user_password">Password</label>
    <input class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
  </div>
  <div class="mb-3">
    <div class="form-check">
      <input class="form-check-input" type="checkbox" value="1" name="user[terms]" id="user_terms">
      <label class="form-check-label" for="user_terms">I accept terms and conditions</label>
      <div class="form-text text-muted">You must first accept terms and conditions in order to continue</div>
    </div>
  </div>
  <input type="submit" name="commit" value="Log In" class="btn btn-primary" data-disable-with="Log In">
</form>

Bootstrap Configuration Options

Here's a list of all possible options you can pass via bootstrap option that can be attached to the bootstrap_form_for, bootstrap_form_with, fields_for, or any field helpers inside of it:

Option Description Default value
disabled An option to disable rails_bootstrap_form helpers. Default rails form builder element is rendered when set to true false
layout Controls layout of form and field helpers. It can be vertical horizontal, or inline. vertical
field_class A CSS class that will be applied to all form fields. nil
help_text Describes help text for the HTML field. Help text is automatically read from translation file. If you want to customize it, you can pass a string. You can also set it false if you do not want help text displayed. nil
label_text An option to customize automatically generated label text. nil
skip_label An option to control whether the label is to be displayed or not. false
hide_label An option to control whether the label is only accessible to a screen readers. false
hide_class A CSS class that will be used when the label is only accessible to a screen readers. visually-hidden
label_class A CSS class that will be applied to all labels when layout is vertical. form-label
additional_label_class An additional CSS class that will be added along with the existing label css classes. nil
prepend Raw or HTML content to be prepended to the field. nil
append Raw or HTML content to be appended to the field. nil
additional_input_group_class An additional CSS class that will be added to existing input group wrapper css classes. nil
floating An option to control whether the field should have a floating label. false
static_field_class A CSS class that will be applied to all static fields. form-control-plaintext
switch An option to control whether the check box should look like Bootstrap switches. false
wrapper An option to control the HTML attributes and options that will be added to a field wrapper. You can set it false if you don't the field to be rendered in a wrapper. {}
size An option to control the size of input groups, buttons, labels, and fields. It can be sm or lg. nil
inline An option to group checkboxes and radio buttons on the same horizontal row. If form layout is inline, this option doesn't get considered. false
label_col_class A CSS class that will be applied to all labels when layout is horizontal. col-form-label
label_col_wrapper_class A CSS class for label column when layout is horizontal. col-sm-2
field_col_wrapper_class A CSS class for field column when layout is horizontal. col-sm-10
render_as_button An option to render submit button using <button type="submit"> instead of <input type="submit">. false

Options defined on the form level will apply to all field helpers. Options defined on field helpers takes precedence over form-level options. Here's an example of a form where one field uses different layout:

bootstrap_option_override

<%= bootstrap_form_for @user do |form| %>
  <%= form.text_field :name %>
  <%= form.email_field :email %>
  <%= form.password_field :password, bootstrap: {layout: :horizontal} %>
  <%= form.check_box :terms %>
  <%= form.primary "Register" %>
<% end %>

This generates the following HTML:

<form novalidate="novalidate" class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
  <div class="mb-3">
    <label class="form-label required" for="user_name">Name</label>
    <input class="form-control" aria-required="true" required="required" type="text" name="user[name]" id="user_name">
  </div>
  <div class="mb-3">
    <label class="form-label required" for="user_email">Email address</label>
    <input class="form-control" aria-required="true" required="required" type="email" name="user[email]" id="user_email">
  </div>
  <div class="row mb-3">
    <label class="col-form-label col-sm-2 required" for="user_password">Password</label>
    <div class="col-sm-10">
      <input class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
    </div>
  </div>
  <div class="mb-3">
    <div class="form-check">
      <input class="form-check-input" type="checkbox" value="1" name="user[terms]" id="user_terms">
      <label class="form-check-label" for="user_terms">I accept terms and conditions</label>
      <div class="form-text text-muted">You must first accept terms and conditions in order to continue</div>
    </div>
  </div>
  <input type="submit" name="commit" value="Register" class="btn btn-primary" data-disable-with="Register">
</form>

Disabling Bootstrap

You can completely disable bootstrap and use default form builder by passing disabled: true option. For example:

<%= form.text_field :username, bootstrap: {disabled: true} %>

This generates the following HTML:

<input type="text" name="user[username]" id="user_username">

Disabling wrapper

In some cases, you may need to disable the default wrapper. You can do this by passing wrapper: false option:

wrapper_false

<%= form.text_field :name, bootstrap: {wrapper: false} %>

This generates the following HTML:

<label class="form-label required" for="user_name">Name</label>
<input class="form-control" aria-required="true" required="required" type="text" name="user[name]" id="user_name">

Add additional CSS class

You can use additional_field_class option at form or field level to add extra CSS classes to the fields.

<%= form.text_field :name, autocomplete: "new-name", bootstrap: {additional_field_class: "custom-class"} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_name">Name</label>
  <input autocomplete="new-name" class="form-control custom-class" aria-required="true" required="required" type="text" name="user[name]" id="user_name">
</div>

You can also use HTML class attribute to add additional CSS class to the single field:

<%= form.text_field :name, autocomplete: "new-name", class: "custom-class" %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_name">Name</label>
  <input autocomplete="new-name" class="form-control custom-class" aria-required="true" required="required" type="text" name="user[name]" id="user_name">
</div>

Here additional_field_class option takes precedance over HTML class attribute:

<%= form.text_field :name, autocomplete: "new-name", bootstrap: {additional_field_class: "custom-class"}, class: "html-class" %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_name">Name</label>
  <input autocomplete="new-name" class="form-control custom-class" aria-required="true" required="required" type="text" name="user[name]" id="user_name">
</div>

Supported Form Helpers

This gem wraps most of the form field helpers. Here's the current list:

check_box                    collection_check_boxes       collection_radio_buttons
collection_select            color_field                  date_field
date_select                  datetime_field               datetime_local_field
datetime_select              email_field                  file_field
grouped_collection_select    hidden_field                 month_field
number_field                 password_field               phone_field
radio_button                 range_field                  rich_text_area
search_field                 select                       static_field
telephone_field              text_area                    text_field
time_field                   time_select                  time_zone_select
url_field                    week_field                   weekday_select

Supported Form Layouts

Vertical Layout

This layout is default layout for the form in which labels are above the fields. In this layout, labels and fields take 100% of the width.

Here's an example of how it looks like:

vertical_layout

<%= bootstrap_form_for @user do |form| %>
  <%= form.email_field :email %>
  <%= form.password_field :password %>
  <%= form.primary "Sign in" %>
<% end %>

This generates the following HTML:

<form novalidate="novalidate" class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
  <div class="mb-3">
    <label class="form-label required" for="user_email">Email address</label>
    <input class="form-control" aria-required="true" required="required" type="email" name="user[email]" id="user_email">
  </div>
  <div class="mb-3">
    <label class="form-label required" for="user_password">Password</label>
    <input class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
  </div>
  <input type="submit" name="commit" value="Sign in" class="btn btn-primary" data-disable-with="Sign in">
</form>

Horizontal Layout

If you want to align label and field side by side, you can use horizontal layout for the form. You can optionally override label_col_wrapper_class and field_col_wrapper_class (they default to col-sm-2 and col-sm-10) at either form level or field level if want to customize space between label and field.

Here's an example of how it looks like by default:

horizontal_layout

<%= bootstrap_form_for @user, bootstrap: {layout: :horizontal} do |form| %>
  <%= form.email_field :email %>
  <%= form.password_field :password %>
  <%= form.primary "Sign in" %>
<% end %>

This generates the following HTML:

<form novalidate="novalidate" class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
  <div class="row mb-3">
    <label class="col-form-label col-sm-2 required" for="user_email">Email address</label>
    <div class="col-sm-10">
      <input class="form-control" aria-required="true" required="required" type="email" name="user[email]" id="user_email">
    </div>
  </div>
  <div class="row mb-3">
    <label class="col-form-label col-sm-2 required" for="user_password">Password</label>
    <div class="col-sm-10">
      <input class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
    </div>
  </div>
  <input type="submit" name="commit" value="Sign in" class="btn btn-primary" data-disable-with="Sign in">
</form>

The label_col_wrapper_class and field_col_wrapper_class css classes can also be customized per control:

horizontal_form_custom_classes

<%= bootstrap_form_for @user, bootstrap: {layout: :horizontal} do |form| %>
  <%= form.text_field :name %>
  <%= form.email_field :username, bootstrap: {label_col_wrapper_class: "col-sm-2", field_col_wrapper_class: "col-sm-6"} %>
  <%= form.password_field :password %>
  <%= form.fields_for :address, include_id: false do |address_form| %>
    <%= address_form.select :country_id, options_for_select(::Country.pluck(:name, :id), address_form.object.country_id),
        {include_blank: "Select Country"} %>
  <% end %>
  <%= form.primary "Register" %>
<% end %>

This generates the following HTML:

<form novalidate="novalidate" class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
  <div class="row mb-3">
    <label class="col-form-label col-sm-2 required" for="user_name">Name</label>
    <div class="col-sm-10">
      <input class="form-control" aria-required="true" required="required" type="text" name="user[name]" id="user_name">
    </div>
  </div>
  <div class="row mb-3">
    <label class="col-form-label col-sm-2" for="user_username">Username</label>
    <div class="col-sm-6">
      <input class="form-control" type="email" name="user[username]" id="user_username">
    </div>
  </div>
  <div class="row mb-3">
    <label class="col-form-label col-sm-2 required" for="user_password">Password</label>
    <div class="col-sm-10">
      <input class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
    </div>
  </div>
  <div class="row mb-3">
    <label class="col-form-label col-sm-2 required" for="user_address_attributes_country_id">Country</label>
    <div class="col-sm-10">
      <select class="form-select" aria-required="true" required="required" name="user[address_attributes][country_id]" id="user_address_attributes_country_id">
        <option value="">Select Country</option>
        <option value="1">India</option>
        <option value="2">Ireland</option>
        <option value="3">United States</option>
        <option value="4">United Kingdom</option>
      </select>
    </div>
  </div>
  <input type="submit" name="commit" value="Register" class="btn btn-primary" data-disable-with="Register">
</form>

Inline Layout

You may choose to render form elements in one line. Please note that this layout won't render all form elements perfectly. Things like errors messages and help text won't show up right.

Here's an example of how it looks like:

inline_layout

<%= bootstrap_form_for @user, bootstrap: {layout: :inline} do |form| %>
  <%= form.email_field :email %>
  <%= form.password_field :password %>
  <%= form.primary "Sign in" %>
<% end %>

This generates the following HTML:

<form novalidate="novalidate" class="new_user row row-cols-lg-auto g-3 align-items-center" id="new_user" action="/users" accept-charset="UTF-8" method="post">
  <div class="col-12">
    <label class="form-label visually-hidden required" for="user_email">Email address</label>
    <input class="form-control" aria-required="true" required="required" placeholder="Email address" type="email" name="user[email]" id="user_email">
  </div>
  <div class="col-12">
    <label class="form-label visually-hidden required" for="user_password">Password</label>
    <input class="form-control" aria-required="true" required="required" placeholder="Password" type="password" name="user[password]" id="user_password">
  </div>
  <div class="col-12">
    <input type="submit" name="commit" value="Sign in" class="btn btn-primary" data-disable-with="Sign in">
  </div>
</form>

Components

rails_bootstrap_form internally supports below components which act as helpers to build fields and their wrappers.

Labels

By default, Rails takes label text from locale file. You can use label_text option to change label text generated by the Rails.

label_text

<%= form.password_field :password, bootstrap: {label_text: "New password"} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_password">New password</label>
  <input class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
</div>

To hide a label, you can set hide_label: true option. This adds the visually-hidden class, which keeps your labels accessible to those using screen readers.

hide_label

<%= form.password_field :password, bootstrap: {hide_label: true} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label visually-hidden required" for="user_password">Password</label>
  <input class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
</div>

To skip a label, you can set skip_label: true option. This will not render label in a field wrapper.

skip_label

<%= form.password_field :password, bootstrap: {skip_label: true} %>

This generates the following HTML:

<div class="mb-3">
  <input class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
</div>

To add additional CSS class to the label, you can use additional_label_class option.

additional_label_class

<%= form.password_field :password, bootstrap: {additional_label_class: "text-danger"} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label text-danger required" for="user_password">Password</label>
  <input class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
</div>

Help Text

The help text is useful when you want to provide helpful information about a field. By default, rails_bootstrap_form takes help text from locale file. If you want to show information regarding any field, you need to add it in locale file of your application. You can also use HTML content for help text.

en:
  activerecord:
    help_texts:
      user:
        password: "A strong password should be at least twelve characters long with combination of uppercase letters, lowercase letters, numbers, and symbols"

help_text_from_translation

<%= form.password_field :password %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_password">Password</label>
  <input class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
  <div class="form-text text-muted">A strong password should be at least twelve characters long with combination of uppercase letters, lowercase letters, numbers, and symbols</div>
</div>

You can customize the help text using help_text option:

help_text

<%= form.password_field :password, bootstrap: {help_text: "Password should not be disclosed to anyone."} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_password">Password</label>
  <input class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
  <div class="form-text text-muted">Password should not be disclosed to anyone.</div>
</div>

You can also disable help text by setting help_text: false option:

help_text_false

<%= form.password_field :password, help_text: false %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_password">Password</label>
  <input class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
</div>

Input Groups

Input groups allow prepending and appending arbitrary html or text to the field.

You can use prepend and/or append options to attach addons to input fields:

input_group_addon

<%= form.number_field :expected_ctc, bootstrap: {prepend: "₹", append: ".00"} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_expected_ctc">Expected CTC</label>
  <div class="input-group">
    <span class="input-group-text">₹</span>
    <input class="form-control" type="number" name="user[expected_ctc]" id="user_expected_ctc">
    <span class="input-group-text">.00</span>
  </div>
</div>

If you want to attach multiple addons to the input, pass them as an array:

input_group_multiple_addons

<%= form.number_field :expected_ctc, bootstrap: {prepend: ["Gross", "₹"], append: [".00", "per annum"]} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_expected_ctc">Expected CTC</label>
  <div class="input-group">
    <span class="input-group-text">Gross</span>
    <span class="input-group-text">₹</span>
    <input class="form-control" type="number" name="user[expected_ctc]" id="user_expected_ctc">
    <span class="input-group-text">.00</span>
    <span class="input-group-text">per annum</span>
  </div>
</div>

You can also prepend and append buttons. Note that these buttons must contain the btn class to generate the correct markup.

input_group_button

<%= form.text_field :search, bootstrap: {append: form.secondary("Search")} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_search">Search</label>
  <div class="input-group">
    <input class="form-control" type="text" name="user[search]" id="user_search">
    <input type="submit" name="commit" value="Search" class="btn btn-secondary" data-disable-with="Search">
  </div>
</div>

To add additional CSS class to the input group wrapper, you can use additional_input_group_class option.

additional_input_group_class

<%= form.number_field :expected_ctc, bootstrap: {prepend: "₹", append: ".00", additional_input_group_class: "custom-class"} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_expected_ctc">Expected CTC</label>
  <div class="input-group custom-class">
    <span class="input-group-text">₹</span>
    <input class="form-control" type="number" name="user[expected_ctc]" id="user_expected_ctc">
    <span class="input-group-text">.00</span>
  </div>
</div>

You can customize size of the input group using size option. Input group supports sm and lg values.

input_group_size

<%= form.number_field :expected_ctc, bootstrap: {prepend: "₹", append: ".00", size: :sm} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_expected_ctc">Expected CTC</label>
  <div class="input-group input-group-sm">
    <span class="input-group-text">₹</span>
    <input class="form-control form-control-sm" type="number" name="user[expected_ctc]" id="user_expected_ctc">
    <span class="input-group-text">.00</span>
  </div>
</div>

Form Helpers

Our form helpers accept the same arguments as the default Rails form helpers. In order to apply addition options of rails_bootstrap_form, bootstrap object is passed in options argument of the helper. Here's an example of how you pass the arguments for each form helper:

check_box

Our check_box helper accepts the same arguments as the default Rails helper. except it don't accept a block as an argument and renders check box and label for you.

check_box

<%= form.check_box :remember_me %>

This generates the following HTML:

<div class="mb-3">
  <div class="form-check">
    <input class="form-check-input" type="checkbox" value="1" name="user[remember_me]" id="user_remember_me">
    <label class="form-check-label" for="user_remember_me">Keep me signed in</label>
  </div>
</div>

You can set switch: true option if you want check box to look like switches.

check_box_switch

<%= form.check_box :remember_me, bootstrap: {switch: true} %>

This generates the following HTML:

<div class="mb-3">
  <div class="form-check form-switch">
    <input class="form-check-input" type="checkbox" value="1" name="user[remember_me]" id="user_remember_me">
    <label class="form-check-label" for="user_remember_me">Keep me signed in</label>
  </div>
</div>

This helper also renders help text if help_text option is set or information of the field is added to the locale file:

check_box_help_text

<%= form.check_box :terms, required: true %>

This generates the following HTML:

<div class="mb-3">
  <div class="form-check">
    <input required="required" class="form-check-input" type="checkbox" value="1" name="user[terms]" id="user_terms">
    <label class="form-check-label required" for="user_terms">I accept terms and conditions</label>
    <div class="form-text text-muted">You must first accept terms and conditions in order to continue</div>
  </div>
</div>

color_field

Our color_field helper accepts the same arguments as the default Rails helper.

color_field

<%= form.color_field :favorite_color %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_favorite_color">Favorite color</label>
  <input class="form-control form-control-color" aria-required="true" required="required" value="#000000" type="color" name="user[favorite_color]" id="user_favorite_color">
</div>

date_field

Our date_field helper accepts the same arguments as the default Rails helper.

date_field

<%= form.date_field :interview_date %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_interview_date">Interview date</label>
  <input class="form-control" value="2023-05-08" type="date" name="user[interview_date]" id="user_interview_date">
</div>

datetime_field

Our datetime_field helper accepts the same arguments as the default Rails helper.

datetime_field

<%= form.datetime_field :interview_datetime %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_interview_datetime">Interview date &amp; time</label>
  <input class="form-control" type="datetime-local" name="user[interview_datetime]" id="user_interview_datetime">
</div>

datetime_local_field

Our datetime_local_field helper accepts the same arguments as the default Rails helper.

datetime_local_field

<%= form.datetime_local_field :interview_datetime %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_interview_datetime">Interview date &amp; time</label>
  <input class="form-control" type="datetime-local" name="user[interview_datetime]" id="user_interview_datetime">
</div>

email_field

Our email_field helper accepts the same arguments as the default Rails helper.

email_field

<%= form.email_field :email %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_email">Email address</label>
  <input class="form-control" aria-required="true" required="required" type="email" name="user[email]" id="user_email">
</div>

fields_for

Our fields_for helper accepts the same arguments as the default Rails helper.

rails_bootstrap_form allows us to set bootstrap option just like bootstrap_form_for and bootstrap_form_with. By setting this option on fields_for, it applies to all the fields defined for that nested form:

fields_for

<%= bootstrap_form_for @user do |form| %>
  <%= form.email_field :email, autocomplete: "new-email" %>
  <%= form.password_field :password, autocomplete: "new-password", bootstrap: {layout: :horizontal} %>
  <%= form.phone_field :mobile_number %>
  <%= form.fields_for :address, include_id: false, bootstrap: {layout: :horizontal} do |address_form| %>
    <%= address_form.select :country_id, options_for_select(::Country.pluck(:name, :id), address_form.object.country_id),
        {include_blank: "Select Country"} %>
  <% end %>
  <%= form.check_box :terms, required: true %>
  <%= form.primary "Register" %>
<% end %>

This generates the following HTML:

<form novalidate="novalidate" class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
  <div class="mb-3">
    <label class="form-label required" for="user_email">Email address</label>
    <input autocomplete="new-email" class="form-control" aria-required="true" required="required" type="email" name="user[email]" id="user_email">
    <div class="form-text text-muted">Please use official email address</div>
  </div>
  <div class="row mb-3">
    <label class="col-form-label col-sm-2 required" for="user_password">Password</label>
    <div class="col-sm-10">
      <input autocomplete="new-password" class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
    </div>
  </div>
  <div class="mb-3">
    <label class="form-label required" for="user_mobile_number">Mobile number</label>
    <input class="form-control" aria-required="true" required="required" type="tel" name="user[mobile_number]" id="user_mobile_number">
  </div>
  <div class="row mb-3">
    <label class="col-form-label col-sm-2 required" for="user_address_attributes_country_id">Country</label>
    <div class="col-sm-10">
      <select class="form-select" aria-required="true" required="required" name="user[address_attributes][country_id]" id="user_address_attributes_country_id">
        <option value="">Select Country</option>
        <option value="1">India</option>
        <option value="2">Ireland</option>
        <option value="3">United States</option>
        <option value="4">United Kingdom</option>
        <option value="5">Spain</option>
        <option value="6">France</option>
        <option value="7">Canada</option>
      </select>
    </div>
  </div>
  <div class="mb-3">
    <div class="form-check">
      <input required="required" class="form-check-input" type="checkbox" value="1" name="user[terms]" id="user_terms">
      <label class="form-check-label required" for="user_terms">I accept terms and conditions</label>
      <div class="form-text text-muted">You must first accept terms and conditions in order to continue</div>
    </div>
  </div>
  <input type="submit" name="commit" value="Register" class="btn btn-primary" data-disable-with="Register">
</form>

By setting bootstrap option on bootstrap_form_for or bootstrap_form_with, this option also applies to all the fields defined in fields_for block:

fields_for_horizontal

<%= bootstrap_form_for @user, bootstrap: {layout: :horizontal} do |form| %>
  <%= form.email_field :email, autocomplete: "new-email" %>
  <%= form.password_field :password, autocomplete: "new-password" %>
  <%= form.phone_field :mobile_number %>
  <%= form.fields_for :address, include_id: false do |address_form| %>
    <%= address_form.select :country_id, options_for_select(::Country.pluck(:name, :id), address_form.object.country_id),
        {include_blank: "Select Country"} %>
  <% end %>
  <%= form.check_box :terms, required: true %>
  <%= form.primary "Register" %>
<% end %>

This generates the following HTML:

<form novalidate="novalidate" class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
  <div class="row mb-3">
    <label class="col-form-label col-sm-2 required" for="user_email">Email address</label>
    <div class="col-sm-10">
      <input autocomplete="new-email" class="form-control" aria-required="true" required="required" type="email" name="user[email]" id="user_email">
      <div class="form-text text-muted">Please use official email address</div>
    </div>
  </div>
  <div class="row mb-3">
    <label class="col-form-label col-sm-2 required" for="user_password">Password</label>
    <div class="col-sm-10">
      <input autocomplete="new-password" class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
    </div>
  </div>
  <div class="row mb-3">
    <label class="col-form-label col-sm-2 required" for="user_mobile_number">Mobile number</label>
    <div class="col-sm-10">
      <input class="form-control" aria-required="true" required="required" type="tel" name="user[mobile_number]" id="user_mobile_number">
    </div>
  </div>
  <div class="row mb-3">
    <label class="col-form-label col-sm-2 required" for="user_address_attributes_country_id">Country</label>
    <div class="col-sm-10">
      <select class="form-select" aria-required="true" required="required" name="user[address_attributes][country_id]" id="user_address_attributes_country_id">
        <option value="">Select Country</option>
        <option value="1">India</option>
        <option value="2">Ireland</option>
        <option value="3">United States</option>
        <option value="4">United Kingdom</option>
        <option value="5">Spain</option>
        <option value="6">France</option>
        <option value="7">Canada</option>
      </select>
    </div>
  </div>
  <div class="row mb-3">
    <div class="col-sm-10 offset-sm-2">
      <div class="form-check">
        <input name="user[terms]" type="hidden" value="0" autocomplete="off">
        <input required="required" class="form-check-input" type="checkbox" value="1" name="user[terms]" id="user_terms">
        <label class="form-check-label required" for="user_terms">I accept terms and conditions</label>
        <div class="form-text text-muted">You must first accept terms and conditions in order to continue</div>
      </div>
    </div>
  </div>
  <input type="submit" name="commit" value="Register" class="btn btn-primary" data-disable-with="Register">
</form>

Options specified at the field level take precedence over those specified at the fields_for level, which take precedence over those specified at the form level.

file_field

Our file_field helper accepts the same arguments as the default Rails helper.

file_field

<%= form.file_field :avatar %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_avatar">Avatar</label>
  <input class="form-control" type="file" name="user[avatar]" id="user_avatar">
</div>

hidden_field

The hidden_field helper in rails_bootstrap_form calls the default Rails helper directly, and does no additional mark-up.

month_field

Our month_field helper accepts the same arguments as the default Rails helper.

month_field

<%= form.month_field :birth_month %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_birth_month">Birth month</label>
  <input class="form-control" type="month" name="user[birth_month]" id="user_birth_month">
</div>

number_field

Our number_field helper accepts the same arguments as the default Rails helper.

number_field

<%= form.number_field :expected_ctc %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_expected_ctc">Expected CTC</label>
  <input class="form-control" type="number" name="user[expected_ctc]" id="user_expected_ctc">
</div>

password_field

Our password_field helper accepts the same arguments as the default Rails helper.

password_field

<%= form.password_field :password %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_password">Password</label>
  <input class="form-control" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
</div>

phone_field

Our phone_field helper accepts the same arguments as the default Rails helper.

phone_field

<%= form.phone_field :mobile_number %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_mobile_number">Mobile number</label>
  <input class="form-control" aria-required="true" required="required" type="tel" name="user[mobile_number]" id="user_mobile_number">
</div>

radio_button

Our radio_button helper accepts the same arguments as the default Rails helper. This helper will render check box and label for you.

radio_button

<%= form.radio_button :gender, :male, bootstrap: {label_text: "Male"} %>

This generates the following HTML:

<div class="mb-3">
  <div class="form-check">
    <input class="form-check-input" type="radio" value="male" name="user[gender]" id="user_gender_male">
    <label class="form-check-label" for="user_gender_male">Male</label>
  </div>
</div>

This helper also renders help text if help_text option is set or information of the field is added to the locale file:

radio_button_help_text

<%= form.radio_button :gender, :male, bootstrap: {label_text: "Male", help_text: "Please select your gender"} %>

This generates the following HTML:

<div class="mb-3">
  <div class="form-check">
    <input class="form-check-input" type="radio" value="male" name="user[gender]" id="user_gender_male">
    <label class="form-check-label" for="user_gender_male">Male</label>
    <div class="form-text text-muted">Please select your gender</div>
  </div>
</div>

range_field

Our range_field helper accepts the same arguments as the default Rails helper.

range_field

<%= form.range_field :excellence %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_excellence">Excellence</label>
  <input class="form-range" type="range" name="user[excellence]" id="user_excellence">
</div>

rich_text_area

Our rich_text_area helper accepts the same arguments as the default Rails helper. This editor is also known as Trix Editor.

rich_text_area

<%= form.rich_text_area :life_story %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_life_story">Life story</label>
  <input type="hidden" name="user[life_story]" id="user_life_story_trix_input_user" autocomplete="off">
  <trix-toolbar id="trix-toolbar-1">
    <div class="trix-button-row">
      <span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools">
        <button type="button" class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" title="Bold" tabindex="-1">Bold</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" title="Italic" tabindex="-1">Italic</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" title="Strikethrough" tabindex="-1">Strikethrough</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-link" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="Link" tabindex="-1">Link</button>
      </span>
      <span class="trix-button-group trix-button-group--block-tools" data-trix-button-group="block-tools">
        <button type="button" class="trix-button trix-button--icon trix-button--icon-heading-1" data-trix-attribute="heading1" title="Heading" tabindex="-1">Heading</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-quote" data-trix-attribute="quote" title="Quote" tabindex="-1">Quote</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-code" data-trix-attribute="code" title="Code" tabindex="-1">Code</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-bullet-list" data-trix-attribute="bullet" title="Bullets" tabindex="-1">Bullets</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-number-list" data-trix-attribute="number" title="Numbers" tabindex="-1">Numbers</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-decrease-nesting-level" data-trix-action="decreaseNestingLevel" title="Decrease Level" tabindex="-1">Decrease Level</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-increase-nesting-level" data-trix-action="increaseNestingLevel" title="Increase Level" tabindex="-1">Increase Level</button>
      </span>
      <span class="trix-button-group trix-button-group--file-tools" data-trix-button-group="file-tools">
        <button type="button" class="trix-button trix-button--icon trix-button--icon-attach" data-trix-action="attachFiles" title="Attach Files" tabindex="-1">Attach Files</button>
      </span>
      <span class="trix-button-group-spacer"></span>
      <span class="trix-button-group trix-button-group--history-tools" data-trix-button-group="history-tools">
        <button type="button" class="trix-button trix-button--icon trix-button--icon-undo" data-trix-action="undo" data-trix-key="z" title="Undo" tabindex="-1">Undo</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-redo" data-trix-action="redo" data-trix-key="shift+z" title="Redo" tabindex="-1">Redo</button>
      </span>
    </div>
    <div class="trix-dialogs" data-trix-dialogs="">
      <div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href">
        <div class="trix-dialog__link-fields">
          <input type="url" name="href" class="trix-input trix-input--dialog" placeholder="Enter a URL…" aria-label="URL" required="" data-trix-input="" disabled="disabled">
          <div class="trix-button-group">
            <input type="button" class="trix-button trix-button--dialog" value="Link" data-trix-method="setAttribute">
            <input type="button" class="trix-button trix-button--dialog" value="Unlink" data-trix-method="removeAttribute">
          </div>
        </div>
      </div>
    </div>
  </trix-toolbar>
  <trix-editor class="trix-content form-control" id="user_life_story" input="user_life_story_trix_input_user" data-direct-upload-url="http://test.host/rails/active_storage/direct_uploads" data-blob-url-template="http://test.host/rails/active_storage/blobs/redirect/:signed_id/:filename" contenteditable="" role="textbox" aria-label="Life story Life story" trix-id="1" toolbar="trix-toolbar-1"></trix-editor>
</div>

search_field

Our search_field helper accepts the same arguments as the default Rails helper.

search_field

<%= form.search_field :search %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_search">Search</label>
  <input class="form-control" type="search" name="user[search]" id="user_search">
</div>

telephone_field

Our telephone_field helper accepts the same arguments as the default Rails helper.

telephone_field

<%= form.telephone_field :mobile_number %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_mobile_number">Mobile number</label>
  <input class="form-control" aria-required="true" required="required" type="tel" name="user[mobile_number]" id="user_mobile_number">
</div>

text_field

Our text_field helper accepts the same arguments as the default Rails helper.

text_field

<%= form.text_field :name %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_name">Name</label>
  <input class="form-control" aria-required="true" required="required" type="text" name="user[name]" id="user_name">
</div>

text_area

Our text_area helper accepts the same arguments as the default Rails helper.

text_area

<%= form.text_area :street %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_street">Street</label>
  <textarea class="form-control" aria-required="true" required="required" name="user[street]" id="user_street"></textarea>
</div>

time_field

Our time_field helper accepts the same arguments as the default Rails helper.

time_field

<%= form.time_field :interview_time %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_interview_time">Interview time</label>
  <input class="form-control" type="time" name="user[interview_time]" id="user_interview_time">
</div>

url_field

Our url_field helper accepts the same arguments as the default Rails helper.

url_field

<%= form.url_field :blog_url %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_blog_url">Blog URL</label>
  <input class="form-control" type="url" name="user[blog_url]" id="user_blog_url">
</div>

week_field

Our week_field helper accepts the same arguments as the default Rails helper.

week_field

<%= form.week_field :winter_holiday_week %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_winter_holiday_week">Winter holiday week</label>
  <input class="form-control" type="week" name="user[winter_holiday_week]" id="user_winter_holiday_week">
</div>

Form Options Helpers

Our form options helpers accept the same arguments as the default Rails form options helpers. In order to apply addition options of rails_bootstrap_form, bootstrap object is passed in options argument of the helper. Here's an example of how you pass the arguments for each form option helper:

select

Our select helper accepts the same arguments as the default Rails helper. Here's an example of how you pass both options and html_options hashes:

select

<%= form.select :fruit_id, options_for_select(::Fruit.pluck(:name, :id), form.object.fruit_id), {include_blank: "Select fruit", bootstrap: {size: :sm, help_text: false}}, {onchange: "this.form.submit();"} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_fruit_id">Favorite fruit</label>
  <select onchange="this.form.submit();" class="form-select" aria-required="true" required="required" name="user[fruit_id]" id="user_fruit_id">
    <option value="">Select fruit</option>
    <option value="1">Mango</option>
    <option value="2">Apple</option>
    <option value="3">Orange</option>
    <option value="4">Watermelon</option>
  </select>
</div>

collection_select

Our collection_select helper accepts the same arguments as the default Rails helper. Here's an example of how you pass both options and html_options hashes:

collection_select

<%= form.collection_select :fruit_id, ::Fruit.all, :id, :name, {include_blank: "Select fruit", bootstrap: {help_text: false}}, {selected: form.object.fruit_id, onchange: "this.form.submit();"} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_fruit_id">Favorite fruit</label>
  <select onchange="this.form.submit();" class="form-select" aria-required="true" required="required" name="user[fruit_id]" id="user_fruit_id">
    <option value="">Select fruit</option>
    <option value="1">Mango</option>
    <option value="2">Apple</option>
    <option value="3">Orange</option>
    <option value="4">Watermelon</option>
  </select>
</div>

grouped_collection_select

Our grouped_collection_select helper accepts the same arguments as the default Rails helper. Here's an example of how you pass both options and html_options hashes:

grouped_collection_select

<%= form.grouped_collection_select :city, ::Country.includes(:cities), :cities, :name, :id, :name, {include_blank: "Select city", bootstrap: {floating: true}}, {onchange: "this.form.submit();"} %>

This generates the following HTML:

<div class="mb-3">
  <div class="form-floating">
    <select onchange="this.form.submit();" class="form-select" aria-required="true" required="required" placeholder="City" name="user[city]" id="user_city">
      <option value="">Select city</option>
      <optgroup label="India">
        <option value="1">Mumbai</option>
        <option value="2">New Delhi</option>
        <option value="3">Kolkata</option>
        <option value="4">Chennai</option>
      </optgroup>
      <optgroup label="Ireland">
        <option value="5">Dublin</option>
        <option value="6">Galway</option>
        <option value="7">Cork</option>
        <option value="8">Belfast</option>
      </optgroup>
      <optgroup label="United States">
        <option value="9">New York</option>
        <option value="10">Los Angeles</option>
        <option value="11">San Francisco</option>
        <option value="12">Chicago</option>
      </optgroup>
      ...
      ...
    </select>
    <label class="form-label required" for="user_city">City</label>
  </div>
</div>

time_zone_select

Our time_zone_select helper accepts the same arguments as the default Rails helper. Here's an example of how you pass both options and html_options hashes:

time_zone_select

<%= form.time_zone_select :timezone, ::ActiveSupport::TimeZone.all, {include_blank: "Select time zone", bootstrap: {label_text: "Preferred time zone"}}, {onchange: "this.form.submit();"} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_timezone">Preferred time zone</label>
  <select onchange="this.form.submit();" class="form-select" name="user[timezone]" id="user_timezone">
    <option value="">Select time zone</option>
    <option value="International Date Line West">(GMT-12:00) International Date Line West</option>
    <option value="American Samoa">(GMT-11:00) American Samoa</option>
    <option value="Midway Island">(GMT-11:00) Midway Island</option>
    <option value="Hawaii">(GMT-10:00) Hawaii</option>
    <option value="Alaska">(GMT-09:00) Alaska</option>
    <option value="Pacific Time (US &amp; Canada)">(GMT-08:00) Pacific Time (US &amp; Canada)</option>
    <option value="Tijuana">(GMT-08:00) Tijuana</option>
    <option value="Arizona">(GMT-07:00) Arizona</option>
    ...
    ...
  </select>
</div>

weekday_select

Our weekday_select helper accepts the same arguments as the default Rails helper. Here's an example of how you pass both options and html_options hashes:

weekday_select

<%= form.weekday_select :weekly_off, {selected: "Monday", bootstrap: {label_text: "Week off"}}, {onchange: "this.form.submit();"} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_weekly_off">Week off</label>
  <select onchange="this.form.submit();" class="form-select" name="user[weekly_off]" id="user_weekly_off">
    <option selected="selected" value="Monday">Monday</option>
    <option value="Tuesday">Tuesday</option>
    <option value="Wednesday">Wednesday</option>
    <option value="Thursday">Thursday</option>
    <option value="Friday">Friday</option>
    <option value="Saturday">Saturday</option>
    <option value="Sunday">Sunday</option>
  </select>
</div>

collection_check_boxes

This helper provides a way to create collection of check boxes. This helper accepts same arguments as default Rails helper except it don't accept a block as an argument and takes care of rendering labels, check boxes, and wrapper for you. collection_check_boxes are rendered by default for multiple option selections, but you can turn them into single selections by passing options[:multiple] = false.

collection_check_boxes

<%= form.collection_check_boxes :skill_ids, ::Skill.all, :id, :name, {bootstrap: {layout: :horizontal, inline: true}, onchange: "this.form.submit();"}, {} %>

This generates the following HTML:

<div class="row mb-3">
  <label class="col-form-label col-sm-2 required" for="user_skill_ids">Skills</label>
  <div class="col-sm-10">
    <div class="rails-bootstrap-forms-collection-check-boxes">
      <input value="" multiple="multiple" autocomplete="off" type="hidden" name="user[skill_ids][]" id="user_skill_ids">
      <div class="form-check form-check-inline">
        <input onchange="this.form.submit();" class="form-check-input" type="checkbox" value="1" name="user[skill_ids][]" id="user_skill_ids_1">
        <label class="form-check-label" for="user_skill_ids_1">Communication</label>
      </div>
      <div class="form-check form-check-inline">
        <input onchange="this.form.submit();" class="form-check-input" type="checkbox" value="2" name="user[skill_ids][]" id="user_skill_ids_2">
        <label class="form-check-label" for="user_skill_ids_2">Problem Solving</label>
      </div>
      <div class="form-check form-check-inline">
        <input onchange="this.form.submit();" class="form-check-input" type="checkbox" value="3" name="user[skill_ids][]" id="user_skill_ids_3">
        <label class="form-check-label" for="user_skill_ids_3">Leadership</label>
      </div>
      <div class="form-check form-check-inline">
        <input onchange="this.form.submit();" class="form-check-input" type="checkbox" value="4" name="user[skill_ids][]" id="user_skill_ids_4">
        <label class="form-check-label" for="user_skill_ids_4">Writing</label>
      </div>
      <div class="form-check form-check-inline">
        <input onchange="this.form.submit();" class="form-check-input" type="checkbox" value="5" name="user[skill_ids][]" id="user_skill_ids_5">
        <label class="form-check-label" for="user_skill_ids_5">Creativity</label>
      </div>
      <div class="form-check form-check-inline">
        <input onchange="this.form.submit();" class="form-check-input" type="checkbox" value="6" name="user[skill_ids][]" id="user_skill_ids_6">
        <label class="form-check-label" for="user_skill_ids_6">Time Management</label>
      </div>
      <div class="form-check form-check-inline">
        <input onchange="this.form.submit();" class="form-check-input" type="checkbox" value="7" name="user[skill_ids][]" id="user_skill_ids_7">
        <label class="form-check-label" for="user_skill_ids_7">Team Work</label>
      </div>
      <div class="form-check form-check-inline">
        <input onchange="this.form.submit();" class="form-check-input" type="checkbox" value="8" name="user[skill_ids][]" id="user_skill_ids_8">
        <label class="form-check-label" for="user_skill_ids_8">Negotiation</label>
      </div>
      <div class="form-check form-check-inline">
        <input onchange="this.form.submit();" class="form-check-input" type="checkbox" value="9" name="user[skill_ids][]" id="user_skill_ids_9">
        <label class="form-check-label" for="user_skill_ids_9">Decision Making</label>
      </div>
      <div class="form-check form-check-inline">
        <input onchange="this.form.submit();" class="form-check-input" type="checkbox" value="10" name="user[skill_ids][]" id="user_skill_ids_10">
        <label class="form-check-label" for="user_skill_ids_10">Management</label>
      </div>
    </div>
    <div class="form-text text-muted">Select your strong skills</div>
  </div>
</div>

If form layout is inline, collection_check_boxes always render inline check boxes.

collection_radio_buttons

This helper provides a way to create collection of radio buttons. This helper accepts same arguments as default Rails helper except it don't accept a block as an argument and takes care of rendering labels, radio button, and wrapper for you.

collection_radio_buttons

<%= form.collection_radio_buttons :fruit_id, ::Fruit.all, :id, :name, {checked: form.object.fruit_id, bootstrap: {layout: :horizontal, inline: true}}, {} %>

This generates the following HTML:

<div class="row mb-3">
  <label class="col-form-label col-sm-2 required" for="user_fruit_id">Favorite fruit</label>
  <div class="col-sm-10">
    <div class="rails-bootstrap-forms-collection-radio-buttons">
      <div class="form-check form-check-inline">
        <input class="form-check-input" type="radio" value="1" name="user[fruit_id]" id="user_fruit_id_1">
        <label class="form-check-label" for="user_fruit_id_1">Mango</label>
      </div>
      <div class="form-check form-check-inline">
        <input class="form-check-input" type="radio" value="2" name="user[fruit_id]" id="user_fruit_id_2">
        <label class="form-check-label" for="user_fruit_id_2">Apple</label>
      </div>
      <div class="form-check form-check-inline">
        <input class="form-check-input" type="radio" value="3" name="user[fruit_id]" id="user_fruit_id_3">
        <label class="form-check-label" for="user_fruit_id_3">Orange</label>
      </div>
      <div class="form-check form-check-inline">
        <input class="form-check-input" type="radio" value="4" name="user[fruit_id]" id="user_fruit_id_4">
        <label class="form-check-label" for="user_fruit_id_4">Watermelon</label>
      </div>
    </div>
    <div class="form-text text-muted">Select your favorite fruit</div>
  </div>
</div>

If form layout is inline, collection_check_boxes always render inline check boxes.

Date Helpers

The multiple selects that the date and time helpers (date_select, time_select, datetime_select) generate are wrapped inside a fieldset.rails-bootstrap-forms-[date|time|datetime]-select tag. This is because Bootstrap automatically styles our controls as blocks. This wrapper fixes this defining these selects as inline-block and a width of auto. In order to apply addition options of rails_bootstrap_form, bootstrap object is passed in options argument of the helper.

date_select

Our date_select helper accepts the same arguments as the default Rails helper. Here's an example of how you pass both options and html_options hashes:

date_select

<%= form.date_select :interview_date, {selected: form.object.interview_date, bootstrap: {label_text: "Choose interview date"}}, {onchange: "this.form.submit();"} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_interview_date">Choose interview date</label>
  <fieldset class="rails-bootstrap-forms-date-select">
    <select id="user_interview_date_1i" name="user[interview_date(1i)]" onchange="this.form.submit();" class="form-select">
      <option value="2018">2018</option>
      <option value="2019">2019</option>
      <option value="2020">2020</option>
      <option value="2021">2021</option>
      <option value="2022">2022</option>
      <option value="2023" selected="selected">2023</option>
      ...
      ...
    </select>
    <select id="user_interview_date_2i" name="user[interview_date(2i)]" onchange="this.form.submit();" class="form-select">
      <option value="1">January</option>
      <option value="2">February</option>
      <option value="3">March</option>
      <option value="4">April</option>
      <option value="5" selected="selected">May</option>
      ...
      ...
    </select>
    <select id="user_interview_date_3i" name="user[interview_date(3i)]" onchange="this.form.submit();" class="form-select">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
      <option value="4">4</option>
      <option value="5">5</option>
      <option value="6">6</option>
      <option value="7">7</option>
      <option value="8" selected="selected">8</option>
      ...
      ...
    </select>
  </fieldset>
</div>

time_select

Our time_select helper accepts the same arguments as the default Rails helper. Here's an example of how you pass both options and html_options hashes:

time_select

<%= form.time_select :interview_time, {selected: form.object.interview_time, bootstrap: {label_text: "Choose interview time"}}, {onchange: "this.form.submit();"} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_interview_time">Choose interview time</label>
  <fieldset class="rails-bootstrap-forms-time-select">
    <input type="hidden" id="user_interview_time_1i" name="user[interview_time(1i)]" value="1" autocomplete="off">
    <input type="hidden" id="user_interview_time_2i" name="user[interview_time(2i)]" value="1" autocomplete="off">
    <input type="hidden" id="user_interview_time_3i" name="user[interview_time(3i)]" value="1" autocomplete="off">
    <select id="user_interview_time_4i" name="user[interview_time(4i)]" onchange="this.form.submit();" class="form-select">
      <option value="00">00</option>
      <option value="01">01</option>
      <option value="02">02</option>
      <option value="03">03</option>
      <option value="04">04</option>
      ...
      ...
    </select>
    :
    <select id="user_interview_time_5i" name="user[interview_time(5i)]" onchange="this.form.submit();" class="form-select">
      <option value="00">00</option>
      <option value="01">01</option>
      <option value="02">02</option>
      <option value="03">03</option>
      <option value="04">04</option>
      <option value="05">05</option>
      ...
      ...
    </select>
  </fieldset>
</div>

datetime_select

Our datetime_select helper accepts the same arguments as the default Rails helper. Here's an example of how you pass both options and html_options hashes:

datetime_select

<%= form.datetime_select :interview_datetime, {selected: form.object.interview_datetime, bootstrap: {label_text: "Choose interview date & time"}}, {onchange: "this.form.submit();"} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_interview_datetime">Choose interview date &amp; time</label>
  <fieldset class="rails-bootstrap-forms-datetime-select">
    <select id="user_interview_datetime_1i" name="user[interview_datetime(1i)]" onchange="this.form.submit();" class="form-select">
      <option value="2018">2018</option>
      <option value="2019">2019</option>
      <option value="2020">2020</option>
      <option value="2021">2021</option>
      ...
      ...
    </select>
    <select id="user_interview_datetime_2i" name="user[interview_datetime(2i)]" onchange="this.form.submit();" class="form-select">
      <option value="1">January</option>
      <option value="2">February</option>
      <option value="3">March</option>
      <option value="4">April</option>
      ...
      ...
    </select>
    <select id="user_interview_datetime_3i" name="user[interview_datetime(3i)]" onchange="this.form.submit();" class="form-select">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
      <option value="4">4</option>
      <option value="5">5</option>
      <option value="6">6</option>
      ...
      ...
    </select>
    —
    <select id="user_interview_datetime_4i" name="user[interview_datetime(4i)]" onchange="this.form.submit();" class="form-select">
      <option value="00">00</option>
      <option value="01">01</option>
      <option value="02">02</option>
      <option value="03">03</option>
      <option value="04">04</option>
      ...
      ...
    </select>
    :
    <select id="user_interview_datetime_5i" name="user[interview_datetime(5i)]" onchange="this.form.submit();" class="form-select">
      <option value="00">00</option>
      <option value="01">01</option>
      <option value="02">02</option>
      <option value="03">03</option>
      <option value="04">04</option>
      ...
      ...
    </select>
  </fieldset>
</div>

Submit Buttons

rails_bootstrap_form allows to easily create submit button for the form. rails_bootstrap_form supports three color variants for submit buttons: secondary, primary, and danger. Submit buttons are supported in vertical, horizontal, and inline layout. Submit buttons in inline form are wrapped inside div.col-12 to properly align on small width devices.

button_helpers

<%= form.secondary "Search" %>
<%= form.primary "Register" %>
<%= form.danger "Delete" %>

This generates the following HTML:

<input type="submit" name="commit" value="Search" class="btn btn-secondary" data-disable-with="Search">
<input type="submit" name="commit" value="Register" class="btn btn-primary" data-disable-with="Register">
<input type="submit" name="commit" value="Delete" class="btn btn-danger" data-disable-with="Delete">

It is also possible to pass additional classes to the button helpers using HTML class attribute and that class will be added along with default class of the submit helper.

button_additional_class

<%= form.primary "Register", class: "register-button" %>

This generates the following HTML:

<input type="submit" name="commit" value="Register" class="register-button btn btn-primary" data-disable-with="Register">

To render submit helper as a button helper, you can set render_as_button: true option or pass a block.

render_as_button

<%= form.primary "Register", bootstrap: {render_as_button: true} %>
<%= form.secondary do %>
  Sign in
<% end %>

This generates the following HTML:

<button name="button" type="submit" class="btn btn-primary">Register</button>
<button name="button" type="submit" class="btn btn-secondary">
  Sign in
</button>

Static controls

rails_bootstrap_form provides form helper static_field to render static controls which internally uses text_field form helper. It sets readonly and disabled attributes on the text field. By default, static_field applies form-control-plaintext CSS class to the control but you can change it by using option static_field_class.

You can create a static controls like this:

static_field

<%= form.static_field :email %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_email">Email address</label>
  <input readonly="readonly" disabled="disabled" value="test@example.com" class="form-control-plaintext" aria-required="true" required="required" type="text" name="user[email]" id="user_email">
</div>

static_field supports all the bootstrap options which are supported by text_field.

Floating Labels

The floating option can be used to enable Bootstrap floating labels. This option is supported on text fields, text areas and dropdowns. Here's an example:

floating_labels

<%= bootstrap_form_for @user, bootstrap: {floating: true} do |form| %>
  <%= form.text_field :name %>
  <%= form.email_field :username %>
  <%= form.password_field :password %>
  <%= form.fields_for :address, include_id: false do |address_form| %>
    <%= address_form.text_area :street %>
    <%= address_form.select :country_id, options_for_select(::Country.pluck(:name, :id), address_form.object.country_id),
        {include_blank: "Select Country"} %>
  <% end %>
  <%= form.primary "Register" %>
<% end %>

This generates the following HTML:

<form novalidate="novalidate" class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
  <div class="mb-3">
    <div class="form-floating">
      <input class="form-control" aria-required="true" required="required" placeholder="Name" type="text" name="user[name]" id="user_name">
      <label class="form-label required" for="user_name">Name</label>
    </div>
  </div>
  <div class="mb-3">
    <div class="form-floating">
      <input class="form-control" placeholder="Username" type="email" name="user[username]" id="user_username">
      <label class="form-label" for="user_username">Username</label>
    </div>
  </div>
  <div class="mb-3">
    <div class="form-floating">
      <input class="form-control" aria-required="true" required="required" placeholder="Password" type="password" name="user[password]" id="user_password">
      <label class="form-label required" for="user_password">Password</label>
    </div>
  </div>
  <div class="mb-3">
    <div class="form-floating">
      <textarea class="form-control" aria-required="true" required="required" placeholder="Street" name="user[address_attributes][street]" id="user_address_attributes_street"></textarea>
      <label class="form-label required" for="user_address_attributes_street">Street</label>
    </div>
  </div>
  <div class="mb-3">
    <div class="form-floating">
      <select class="form-select" aria-required="true" required="required" placeholder="Country" name="user[address_attributes][country_id]" id="user_address_attributes_country_id">
        <option value="">Select Country</option>
        <option value="1">India</option>
        <option value="2">Ireland</option>
        <option value="3">United States</option>
        <option value="4">United Kingdom</option>
      </select>
      <label class="form-label required" for="user_address_attributes_country_id">Country</label>
    </div>
  </div>
  <input type="submit" name="commit" value="Register" class="btn btn-primary" data-disable-with="Register">
</form>

rails_bootstrap_form automatically disables floating labels for unsupported helpers.

Validation and Errors

By default, rails_bootstrap_form generations in-line errors which appear below the field.

Inline Errors

By default, fields that have validation errors will be outlined in red and the error will be displayed below the field. Here's an example:

inline_errors

<%= bootstrap_form_for @user do |form| %>
  <%= form.email_field :email %>
  <%= form.password_field :password %>
  <%= form.primary "Register" %>
<% end %>

This generates the following HTML:

<form novalidate="novalidate" class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
  <div class="mb-3">
    <label class="form-label required is-invalid" for="user_email">Email address</label>
    <input class="form-control is-invalid" aria-required="true" required="required" type="email" name="user[email]" id="user_email">
    <div class="invalid-feedback">can't be blank</div>
    <div class="form-text text-muted">Please use official email address</div>
  </div>
  <div class="mb-3">
    <label class="form-label required is-invalid" for="user_password">Password</label>
    <input class="form-control is-invalid" aria-required="true" required="required" type="password" name="user[password]" id="user_password">
    <div class="invalid-feedback">can't be blank</div>
  </div>
  <input type="submit" name="commit" value="Register" class="btn btn-primary" data-disable-with="Register">
</form>

Inline errors are also supported if the field is wrapped inside of input group and has floating label:

floating_inline_errors

<%= form.text_field :expected_ctc, bootstrap: {floating: true, prepend: "$", append: "0.0"} %>

This generates the following HTML:

<div class="mb-3">
  <div class="input-group has-validation">
    <span class="input-group-text">$</span>
    <div class="form-floating is-invalid">
      <input class="form-control is-invalid" aria-required="true" required="required" placeholder="Expected CTC" type="text" value="" name="user[expected_ctc]" id="user_expected_ctc">
      <label class="form-label required is-invalid" for="user_expected_ctc">Expected CTC</label>
    </div>
    <span class="input-group-text">0.0</span>
    <div class="invalid-feedback">can't be blank</div>
  </div>
</div>

The has-validation CSS class is added to an input group when the field has errors. The is-invalid CSS class is added to floating label container when field with floating label has errors.

Required Fields

A label that is associated with a mandatory field is automatically annotated with a required CSS class. rails_bootstrap_form provides styling for required fields. You're also free to add any appropriate CSS to style required fields as desired.

The label required class is determined based on the definition of a presence validator with the associated model attribute. Presently this is one of: ActiveRecord::Validations::PresenceValidator or ActiveModel::Validations::PresenceValidator.

In cases where this behaviour is undesirable, use the required option to force the class to be present or absent:

required_field

<%= form.date_field :birth_date, required: false %>
<%= form.url_field :blog_url, required: true %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label" for="user_birth_date">Birth date</label>
  <input class="form-control" type="date" name="user[birth_date]" id="user_birth_date">
</div>
<div class="mb-3">
  <label class="form-label required" for="user_blog_url">Blog URL</label>
  <input required="required" class="form-control" aria-required="true" type="url" name="user[blog_url]" id="user_blog_url">
</div>

Required belongs_to associations

Adding a form control for a belongs_to associated field will automatically pick up the associated presence validator.

belongs_to_presence

<%= form.collection_radio_buttons :fruit_id, ::Fruit.all, :id, :name, {checked: form.object.fruit_id} %>

This generates the following HTML:

<div class="mb-3">
  <label class="form-label required" for="user_fruit_id">Favorite fruit</label>
  <div class="rails-bootstrap-forms-collection-radio-buttons">
    <div class="form-check form-check-inline">
      <input class="form-check-input" type="radio" value="1" name="user[fruit_id]" id="user_fruit_id_1">
      <label class="form-check-label" for="user_fruit_id_1">Mango</label>
    </div>
    <div class="form-check form-check-inline">
      <input class="form-check-input" type="radio" value="2" name="user[fruit_id]" id="user_fruit_id_2">
      <label class="form-check-label" for="user_fruit_id_2">Apple</label>
    </div>
    <div class="form-check form-check-inline">
      <input class="form-check-input" type="radio" value="3" name="user[fruit_id]" id="user_fruit_id_3">
      <label class="form-check-label" for="user_fruit_id_3">Orange</label>
    </div>
    <div class="form-check form-check-inline">
      <input class="form-check-input" type="radio" value="4" name="user[fruit_id]" id="user_fruit_id_4">
      <label class="form-check-label" for="user_fruit_id_4">Watermelon</label>
    </div>
  </div>
  <div class="form-text text-muted">Select your favorite fruit</div>
</div>

Internationalization

rails_bootstrap_form follows standard rails conventions so it's i18n-ready. See more here

Other Tips

Empty But Visible Labels

Some third party plug-ins require an empty but visible label on an input control. The hide_label option generates a label that won't appear on the screen, but it's considered invisible and therefore doesn't work with such a plug-in. An empty label (e.g. "") causes the underlying Rails helpers to generate a label based on the field's attribute's name.

The solution is to use a zero-width character for the label, or some other "empty" HTML. For example:

bootstrap: {label_text: "&#8203;".html_safe}

or

bootstrap: {label_text: "<span></span>".html_safe}

Contributing

I welcome contributions. If you wish to contribute in rails_bootstrap_form, please review the Contributing document first.

License

Copyright 2023 Harshal V. LADHE, Released under the MIT License