TwitterBootstrapFormBuilder
A gem for building horizontal (vertial/search/inline coming soon) Twitter Bootstrap forms, automagically handling the control-group markup, field labels and inline-error messages.
Installation
Add this line to your application's Gemfile:
gem 'twitter-bootstrap-form-builder'
And then execute:
$ bundle
Or install it yourself as:
$ gem install twitter-bootstrap-form-builder
QuickStart
app/helpers/application_helper.rb
module ApplicationHelper
# Replace form_for
include MNE::TwitterBootstrapFormBuilder
end
Using the form builder
<% # Labels and control-group markup are handled by the form builder %>
<%= form_for @post do |f| %>
<%= f.text_field :topic %>
<%= f.text_area :body %>
<div class="form-actions">
<%= f.submit "Create Post" %>
</div>
<% end %>
Usage
Twitter Bootstrap FormBuilder is designed to output all the markup required to build horizontal forms, with minimal typing.
After installing the Gem, you can use the special form_for
helper by mixing TwitterBootstrapFormBuilder::Helper
into your Helper modules, which will automatically add the form-horizontal
class to your <form>
tag,
and set the :builder
to TwitterBootstrapFormBuilder
. That is, the following are roughly equivalent:
# Using the TBFB helper:
form_for @post do |f|
# Using the regular form_for helper
form_for @post, :builder => MNE::TwitterBootstrapFormBuilder::FormBuilder, :html => { :class => "form-horizontal" } do |f|
Using the FormBuilder:
The various *_field
and select
methods will output the full markup for a control group, including labels.
The following text_field
...
<%= form_for @post do |f| %>
<%= f.text_field :subject %>
Outputs the following HTML:
<div class="text_field control-group subject">
<label for="post_subject">Subject</label>
<div class="controls">
<input type="text" name="post[subject]" id="post_subject" value="..." />
</div>
</div>
If you need to override the text of the label, use :label
:
<%= f.text_field :email, :label => "Email Address" %>
If you want to turn off the helper entirely for one field and output just the input/select/textarea element,
exactly as if you were calling the regular FormBuilder#text_field
, use :label => false
:
<%= f.text_field :email, :label => false %> # <input type="text" id="post_email" />
To disable the Bootstrap FormBuilder for an entire form, use :bootstrap => false
with form_for
:
<%= form_for @post, :bootstrap => false do |f| %>
To render the field within the Bootstrap control-group markup but without a label tag,
use :label => nil
:
<%= f.text_field :email, :label => nil %>
Checkboxes are a special case. They can contain two labels in a horizontal form, on to the left and one to the right.
The left label uses the :label
option and works as expected.
The right label is controled by the :text
option.
Example:
<%= f.check_box :hide_email, :text=> "Do not display my email in my post" %>
Produces the following HTML:
<div class="control-group hide_email">
<label class="control-label" for="post_hide_email">Hide email</label>
<div class="controls">
<label class="checkbox" for="post_hide_email">
<input name="post[hide_email]" type="hidden" value="0" />
<input id="post_hide_email" name="post[hide_email]" type="checkbox" value="1" />
Do not display my email in my post
</label>
</div>
</div>
Errors and validation
The TwitterBootstrapFormBuilder relies on the dynamic_form gem to output inline error messages.
Outputting a field with errors will add an inline error message and decorate the top-level control-group with an
error
class, causing the field inside to be outlined in Red by bootstrap.css
Given a post with a "can't be blank" error on the topic field:
<%= form_for @post do |f| %>
<%= f.text_field :topic %>
<% end %>
The following will be produced (a mixture of Rail's field_with_errors
and Bootstrap-specific classes):
<div class="text_field control-group topic error">
<div class="field_with_errors">
<label for="post_topic">Topic</label>
</div>
<div class="controls">
<div class="field_with_errors">
<input type="text" name="post[topic]" value="..." />
</div>
<p class="help-block">Topic can't be blank</p>
</div>
</div>
Note that both the label
and input
elements are still wrapped in <div class="field_with_errors">
by the base
FormBuilder. In addition, a <p class="help-block">
is output below the field containing the error message.
Rendering just some fields:
<%= fields_for @post, :builder => MNE::TwitterBootstrapFormBuilder::FormBuilder do |f| %>
Other helpers
If you want to output your own control group, you can use the control_group
method to help with the markup.
<%= f.control_group :topic %> <!-- div class="control-group topic [error]" -->
<%= f.label :topic %>
<div class="controls">
<%= f.text_field :topic, :label => false %>
<div class="errors">
<%= f.errors_for :topic %><!-- as provided by dynamic_form -->
</div>
</div>
<% end %>
Examples
Here is a basic form for a PhotoSet, which contains a title and description attribute.
The form has been posted back, causing a validates_presence_of
validator to fail on the title
field:
Form:
<%= form_for [:admin, @photo_set] do |f| %>
<%= f.text_field :title %>
<%= f.text_area :description %>
<div class="form-actions">
<%= f.submit "Create Photo Set" %>
</div>
<% end %>
Output (cleaned up and indented):
<form accept-charset="UTF-8" action="/admin/photo_sets" class="form-horizontal" id="new_photo_set" method="post">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value="nVRM9bXgeD2s/WGum+fJMy9dMYSNVCzYR6/U0Pg+068=" />
</div>
<div class="text_field control-group title error">
<div class="field_with_errors">
<label class="control-label" for="photo_set_title">Title</label>
</div>
<div class="controls">
<div class="field_with_errors">
<input id="photo_set_title" name="photo_set[title]" size="30" type="text" value="" />
</div>
<p class="help-block">Title can't be blank</p>
</div>
</div>
<div class="text_area control-group description">
<label class="control-label" for="photo_set_description">Description</label>
<div class="controls">
<textarea cols="40" id="photo_set_description" name="photo_set[description]" rows="20">
</textarea>
</div>
</div>
<div class="form-actions">
<input name="commit" type="submit" value="Create Photo Set" />
</div>
</form>
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Added some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request