bootstrap_form
is a Rails form builder that makes it super easy to integrate Bootstrap v5-style forms into your Rails application. It provides form helpers that augment the Rails form helpers. bootstrap_forms
's form helpers generate the form field and its label and all the Bootstrap mark-up required for proper Bootstrap display. bootstrap_form
also provides:
bootstrap_form
's validation error handling and do it yourself. Note that this applies to Rails-generated validation messages. HTML 5 client-side validation and Rails validation out of the box don't really work well together. One discussion of the challenges and some solutions is hererequired
attribute on required fields.bootstrap_form
can't do.Some other nice things that bootstrap_form
does for you are:
.erb
files.bootstrap_form
works like the standard Rails form helpers, and this README assumes you know how they work. You start a form with one of bootstrap_form_with
, bootstrap_form_for
, or bootstrap_form_tag
in a view file. You get a form builder that calls the bootstrap_form
helpers instead of the standard Rails helpers. You use that form builder in the view file to render one or more form fields.
bootstrap_form
supports at a minimum the currently supported versions of Ruby and Rails:
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 bootstrap_form
gem to your Gemfile
:
gem "bootstrap_form", "~> 5.4"
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_forms
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_forms.css";
To get started, use the bootstrap_form_for
helper in place of the Rails form_for
helper. Here's an example:
<%= bootstrap_form_for(@user) do |f| %>
<%= f.email_field :email %>
<%= f.password_field :password %>
<%= f.check_box :remember_me %>
<%= f.submit "Log In" %>
<% end %>
This generates the following HTML:
<form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
<div class="mb-3">
<label class="form-label required" for="user_email">Email</label>
<input class="form-control" id="user_email" name="user[email]" required="required" type="email" value="[email protected]">
</div>
<div class="mb-3">
<label class="form-label" for="user_password">Password</label>
<input class="form-control" id="user_password" name="user[password]" type="password">
</div>
<div class="form-check mb-3">
<input autocomplete="off" name="user[remember_me]" type="hidden" value="0">
<input class="form-check-input" id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
<label class="form-check-label" for="user_remember_me">Remember me</label>
</div>
<input class="btn btn-secondary" data-disable-with="Log In" name="commit" type="submit" value="Log In">
</form>
If your form is not backed by a model, use the bootstrap_form_tag
. Usage of this helper is the same as bootstrap_form_for
, except no model object is passed in as the first argument. Here's an example:
<%= bootstrap_form_tag url: '/subscribe' do |f| %>
<%= f.email_field :email, value: '[email protected]' %>
<%= f.submit %>
<% end %>
This generates:
<form accept-charset="UTF-8" action="/subscribe" method="post">
<div class="mb-3">
<label class="form-label" for="email">Email</label>
<input class="form-control" id="email" name="email" type="email" value="[email protected]">
</div>
<input class="btn btn-secondary" data-disable-with="Save " name="commit" type="submit" value="Save ">
</form>
To get started, just use the bootstrap_form_with
helper in place of form_with
. Here's an example:
<%= bootstrap_form_with(model: @user, local: true) do |f| %>
<%= f.email_field :email %>
<%= f.password_field :password, help: 'A good password should be at least six characters long' %>
<%= f.check_box :remember_me %>
<%= f.submit "Log In" %>
<% end %>
This generates:
<form accept-charset="UTF-8" action="/users" method="post">
<div class="mb-3">
<label class="form-label required" for="user_email">Email</label>
<input class="form-control" id="user_email" name="user[email]" required="required" type="email" value="[email protected]">
</div>
<div class="mb-3">
<label class="form-label" for="user_password">Password</label>
<input class="form-control" id="user_password" name="user[password]" type="password">
<small class="form-text text-muted">A good password should be at least six characters long</small>
</div>
<div class="form-check mb-3">
<input autocomplete="off" name="user[remember_me]" type="hidden" value="0">
<input class="form-check-input" id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
<label class="form-check-label" for="user_remember_me">Remember me</label>
</div>
<input class="btn btn-secondary" data-disable-with="Log In" name="commit" type="submit" value="Log In">
</form>
bootstrap_form_with
supports both the model:
and url:
use cases
in form_with
.
form_with
has some important differences compared to form_for
and form_tag
, and these differences apply to bootstrap_form_with
. A good summary of the differences can be found at: https://m.patrikonrails.com/rails-5-1s-form-with-vs-old-form-helpers-3a5f72a8c78a, or in the Rails documentation.
Adding fields for a different object without nesting can be achieved using the bootstrap_fields_for
and
bootstrap_fields
helpers in the same way it is done in Rails.
<%= bootstrap_form_with model: @user do |f| %>
<%= f.email_field :email %>
<%= bootstrap_fields_for :parent do |pf| %>
<%= pf.email_field :email, label: 'Parent email' %>
<% end %>
<%= bootstrap_fields @user.address do |af| %>
<%= af.text_field :street_name %>
<% end %>
<%= f.primary "Save" %>
<% end %>
Generated HTML:
<form accept-charset="UTF-8" action="/users" method="post">
<div class="mb-3">
<label class="form-label required" for="user_email">Email</label>
<input class="form-control" id="user_email" name="user[email]" required="required" type="email" value="[email protected]">
</div>
<div class="mb-3">
<label class="form-label" for="parent_email">Parent email</label>
<input class="form-control" id="parent_email" name="parent[email]" type="email">
</div>
<div class="mb-3">
<label class="form-label" for="street_name">Street name</label>
<input class="form-control" id="street_name" name="street_name" type="text">
</div>
<input class="btn btn-primary" data-disable-with="Save" name="commit" type="submit" value="Save">
</form>
bootstrap_form
can be used out-of-the-box without any configuration. However, bootstrap_form
does have an optional configuration file at config/initializers/bootstrap_form.rb
for setting options that affect all generated forms in an application.
The current configuration options are:
Option | Default value | Description |
---|---|---|
default_form_attributes |
bootstrap_form versions 3 and 4 added a role="form" attribute to all forms. The W3C validator will raise a warning on forms with a role="form" attribute. bootstrap_form version 5 drops this attribute by default. Set this option to { role: "form" } to make forms non-compliant with W3C, but generate the role="form" attribute like bootstrap_form versions 3 and 4. |
Example:
# config/initializers/bootstrap_form.rb
BootstrapForm.configure do |c|
c.default_form_attributes = { role: "form" } # to make forms non-compliant with W3C.
end
bootstrap_form
provides its own version of the following Rails form helpers:
button email_field search_field
check_box file_field select
collection_check_boxes grouped_collection_select submit
collection_radio_buttons hidden_field (not wrapped, but supported) telephone_field
collection_select month_field text_area
color_field number_field text_field
date_field password_field time_field
date_select phone_field time_select
datetime_field radio_button time_zone_select
datetime_local_field range_field url_field
datetime_select rich_text_area week_field
By default, the helpers generate a label
tag, and an input
, select
, or textarea
tag, by calling the Rails label
helper, and then the Rails helper with the same name as the bootstrap_form
helper.
The bootstrap_form
helpers accept the same options as the standard Rails form helpers, and pass those options through to the Rails helper. They also accept additional options, described in the following section.
Many of the helpers accept the same options. The exceptions are:
button, check_box, collection_check_boxes, collection_radio_buttons, collection_select, date_select, datetime_select, file_field, grouped_collection_select, hidden_field, radio_button, rich_text_area, select, submit, time_select, time_zone_select
The options for the form helpers that aren't in the exceptions list are described in the following sub-sections:
Use the label
option if you want to specify the field's label text:
<%= f.password_field :password_confirmation, label: "Confirm Password" %>
This generates:
<div class="mb-3">
<label class="form-label" for="user_password_confirmation">Confirm Password</label>
<input class="form-control" id="user_password_confirmation" name="user[password_confirmation]" type="password">
</div>
To hide a label, use the hide_label: true
option. This adds the visually-hidden
class, which keeps your labels accessible to those using screen readers.
<%= f.text_area :comment, hide_label: true, placeholder: "Leave a comment..." %>
This generates:
<div class="mb-3">
<label class="visually-hidden" for="user_comment">Comment</label>
<textarea class="form-control" id="user_comment" name="user[comment]" placeholder="Leave a comment...">
</textarea>
</div>
To add custom classes to the field's label:
<%= f.email_field :email, label_class: "custom-class" %>
This generates:
<div class="mb-3">
<label class="custom-class required" for="user_email">Email</label>
<input class="form-control" id="user_email" name="user[email]" required="required" type="email" value="[email protected]">
</div>
Or you can add the label as input placeholder instead (this automatically hides the label):
<%= f.email_field :email, value: '', label_as_placeholder: true %>
This generates:
<div class="mb-3">
<label class="visually-hidden required" for="user_email">Email</label>
<input class="form-control" id="user_email" name="user[email]" placeholder="Email" required="required" type="email" value="">
</div>
To specify the class of the generated input tag, use the control_class
option:
<%= f.text_field :email, control_class: "custom-class" %>
This generates:
<div class="mb-3">
<label class="form-label required" for="user_email">Email</label>
<input class="custom-class" id="user_email" name="user[email]" required="required" type="text" value="[email protected]">
</div>
To add help text, use the help
option:
<%= f.password_field :password, help: "Must be at least 6 characters long" %>
This generates:
<div class="mb-3">
<label class="form-label" for="user_password">Password</label>
<input class="form-control" id="user_password" name="user[password]" type="password">
<small class="form-text text-muted">Must be at least 6 characters long</small>
</div>
This gem is also aware of help messages in locale translation files (i18n):
en:
activerecord:
help:
user:
password: "A good password should be at least six characters long"
Help translations containing HTML should follow the convention of appending _html
to the name:
en:
activerecord:
help:
user:
password_html: "A <strong>good</strong> password should be at least six characters long"
If your model name has multiple words (like SuperUser
), the key on the
translation file should be underscored (super_user
).
You can override help translations for a particular field by passing the help
option or turn them off completely by passing help: false
.
You can pass prepend
and/or append
options to input fields:
<%= f.text_field :price, prepend: "$", append: ".00" %>
This generates:
<div class="mb-3">
<label class="form-label" for="user_price">Price</label>
<div class="input-group">
<span class="input-group-text">$</span>
<input class="form-control" id="user_price" name="user[price]" type="text">
<span class="input-group-text">.00</span>
</div>
</div>
If you want to attach multiple items to the input, pass them as an array:
<% icon = capture do %><i class="bi bi-currency-dollar"></i><% end %>
<%= f.text_field :price, prepend: ['Net', icon], append: ['.00', 'per day'] %>
This generates:
<div class="mb-3">
<label class="form-label" for="user_price">Price</label>
<div class="