Skip to content

Commit

Permalink
Allow setting wrapper attributes for check boxes and radios buttons
Browse files Browse the repository at this point in the history
  • Loading branch information
UweKubosch committed Jun 7, 2022
1 parent 1446613 commit 6739cd7
Show file tree
Hide file tree
Showing 33 changed files with 71 additions and 36 deletions.
97 changes: 65 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -652,11 +652,33 @@ This generates:
</div>
```

You can also add a style to the tag using the `wrapper` option:

![Example 21](demo/doc/screenshots/bootstrap/readme/21_example.png "Example 21")
```erb
<%= f.check_box :skilled, inline: true, wrapper: {style: "color: green"} %>
<%= f.radio_button :skill_level, 0, label: "Novice", inline: true, wrapper: {class: 'w-auto', style: "color: red"} %>
```

This generates:

```html
<div class="form-check form-check-inline mb-3" style="color: green">
<input autocomplete="off" name="user[skilled]" type="hidden" value="0">
<input class="form-check-input" id="user_skilled" name="user[skilled]" type="checkbox" value="1">
<label class="form-check-label" for="user_skilled">Skilled</label>
</div>
<div class="form-check form-check-inline w-auto" style="color: red">
<input class="form-check-input" id="user_skill_level_0" name="user[skill_level]" type="radio" value="0">
<label class="form-check-label" for="user_skill_level_0">Novice</label>
</div>
```

### Switches

To render checkboxes as switches with Bootstrap 4.2+, use `switch: true`:

![Example 21](demo/doc/screenshots/bootstrap/readme/21_example.png "Example 21")
![Example 22](demo/doc/screenshots/bootstrap/readme/22_example.png "Example 22")
```erb
<%= f.check_box :remember_me, switch: true %>
```
Expand All @@ -676,7 +698,7 @@ This generates:
`bootstrap_form` also provides helpers that automatically create the
`form_group` and the `radio_button`s or `check_box`es for you:

![Example 22](demo/doc/screenshots/bootstrap/readme/22_example.png "Example 22")
![Example 23](demo/doc/screenshots/bootstrap/readme/23_example.png "Example 23")
```erb
<%= f.collection_radio_buttons :skill_level, Skill.all, :id, :name %>
<%= f.collection_check_boxes :skills, Skill.all, :id, :name %>
Expand Down Expand Up @@ -741,7 +763,7 @@ This generates:

You can create a static control like this:

![Example 23](demo/doc/screenshots/bootstrap/readme/23_example.png "Example 23")
![Example 25](demo/doc/screenshots/bootstrap/readme/25_example.png "Example 25")
```erb
<%= f.static_control :email %>
```
Expand All @@ -757,18 +779,29 @@ This generates:

Here's the output for a horizontal layout:

![Example 26](demo/doc/screenshots/bootstrap/readme/26_example.png "Example 26")
```erb
<%= bootstrap_form_for(@user, layout: :horizontal) do |f| %>
<%= f.static_control :email %>
<% end %>
```

This generates:

```html
<div class="mb-3">
<label class="form-label col-sm-2 form-control-label" for="user_email">Email</label>
<div class="col-sm-10">
<input class="form-control-plaintext" id="user_email" name="user[email]" readonly="readonly" type="text" value="test@email.com"/>
<form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
<div class="mb-3 row">
<label class="form-label col-form-label col-sm-2 required" for="user_email">Email</label>
<div class="col-sm-10">
<input class="form-control-plaintext" id="user_email" name="user[email]" readonly type="text" value="steve@example.com">
</div>
</div>
</div>
</form>
```

You can also create a static control that isn't based on a model attribute:

![Example 24](demo/doc/screenshots/bootstrap/readme/24_example.png "Example 24")
![Example 27](demo/doc/screenshots/bootstrap/readme/27_example.png "Example 27")
```erb
<%= f.static_control :field_name, label: "Custom Static Control", value: "Content Here" %>
```
Expand All @@ -786,7 +819,7 @@ This generates:

You can also create the static control the following way, if you don't need to get the value of the static control as a parameter when the form is submitted:

![Example 25](demo/doc/screenshots/bootstrap/readme/25_example.png "Example 25")
![Example 28](demo/doc/screenshots/bootstrap/readme/28_example.png "Example 28")
```erb
<%= f.static_control label: "Custom Static Control", value: "Content Here", name: nil %>
```
Expand Down Expand Up @@ -820,7 +853,7 @@ this defining these selects as `inline-block` and a width of `auto`.
The `btn btn-secondary` CSS classes are automatically added to your submit
buttons.

![Example 26](demo/doc/screenshots/bootstrap/readme/26_example.png "Example 26")
![Example 29](demo/doc/screenshots/bootstrap/readme/29_example.png "Example 29")
```erb
<%= f.submit %>
```
Expand All @@ -834,7 +867,7 @@ This generates:
You can also use the `primary` helper, which adds `btn btn-primary` to your
submit button:

![Example 27](demo/doc/screenshots/bootstrap/readme/27_example.png "Example 27")
![Example 30](demo/doc/screenshots/bootstrap/readme/30_example.png "Example 30")
```erb
<%= f.primary "Optional Label" %>
```
Expand All @@ -847,7 +880,7 @@ This generates:

You can specify your own classes like this:

![Example 28](demo/doc/screenshots/bootstrap/readme/28_example.png "Example 28")
![Example 31](demo/doc/screenshots/bootstrap/readme/31_example.png "Example 31")
```erb
<%= f.submit "Log In", class: "btn btn-success" %>
```
Expand All @@ -863,7 +896,7 @@ it will be rendered as an HTML button, instead of an input tag. This allows you
to specify HTML content and styling for your buttons (such as adding
illustrative icons to them). For example, the following statements

![Example 29](demo/doc/screenshots/bootstrap/readme/29_example.png "Example 29")
![Example 32](demo/doc/screenshots/bootstrap/readme/32_example.png "Example 32")
```erb
<%= f.primary "Save changes <span class='fa fa-save'></span>".html_safe, render_as_button: true %>
Expand Down Expand Up @@ -897,7 +930,7 @@ Bootstrap classes), or for element targeting via CSS classes.
Be aware, however, that using the `class` option will discard any extra classes
you add. As an example, the following button declarations

![Example 30](demo/doc/screenshots/bootstrap/readme/30_example.png "Example 30")
![Example 33](demo/doc/screenshots/bootstrap/readme/33_example.png "Example 33")
```erb
<%= f.primary "My Nice Button", extra_class: 'my-button' %>
Expand All @@ -917,7 +950,7 @@ will be rendered as

If you're using Rails 6, `bootstrap_form` supports the `rich_text_area` helper.

![Example 31](demo/doc/screenshots/bootstrap/readme/31_example.png "Example 31")
![Example 34](demo/doc/screenshots/bootstrap/readme/34_example.png "Example 34")
```erb
<%= f.rich_text_area(:life_story) %>
```
Expand Down Expand Up @@ -985,7 +1018,7 @@ The `hidden_field` helper in `bootstrap_form` calls the Rails helper directly, a
If you want to use the original Rails form helpers for a particular field,
append `_without_bootstrap` to the helper:

![Example 32](demo/doc/screenshots/bootstrap/readme/32_example.png "Example 32")
![Example 35](demo/doc/screenshots/bootstrap/readme/35_example.png "Example 35")
```erb
<%= f.text_field_without_bootstrap :email %>
```
Expand All @@ -1007,7 +1040,7 @@ To use an inline-layout form, use the `layout: :inline` option. To hide labels,
use the `hide_label: true` option, which keeps your labels accessible to those
using screen readers.

![Example 33](demo/doc/screenshots/bootstrap/readme/33_example.png "Example 33")
![Example 36](demo/doc/screenshots/bootstrap/readme/36_example.png "Example 36")
```erb
<%= bootstrap_form_for(@user, layout: :inline) do |f| %>
<%= f.email_field :email, hide_label: true %>
Expand Down Expand Up @@ -1042,7 +1075,7 @@ This generates:

To skip label rendering at all, use `skip_label: true` option.

![Example 34](demo/doc/screenshots/bootstrap/readme/34_example.png "Example 34")
![Example 37](demo/doc/screenshots/bootstrap/readme/37_example.png "Example 37")
```erb
<%= f.password_field :password, skip_label: true %>
```
Expand All @@ -1064,7 +1097,7 @@ To use a horizontal-layout form with labels to the left of the control, use the
In the example below, the checkbox and submit button have been wrapped in a
`form_group` to keep them properly aligned.

![Example 35](demo/doc/screenshots/bootstrap/readme/35_example.png "Example 35")
![Example 38](demo/doc/screenshots/bootstrap/readme/38_example.png "Example 38")
```erb
<%= bootstrap_form_for(@user, layout: :horizontal, label_col: "col-sm-2", control_col: "col-sm-10") do |f| %>
<%= f.email_field :email %>
Expand Down Expand Up @@ -1114,7 +1147,7 @@ This generates:

The `label_col` and `control_col` css classes can also be changed per control:

![Example 36](demo/doc/screenshots/bootstrap/readme/36_example.png "Example 36")
![Example 39](demo/doc/screenshots/bootstrap/readme/39_example.png "Example 39")
```erb
<%= bootstrap_form_for(@user, layout: :horizontal) do |f| %>
<%= f.email_field :email %>
Expand Down Expand Up @@ -1171,7 +1204,7 @@ end

Control col wrapper class can be modified with `add_control_col_class`. This option will preserve column definition:

![Example 37](demo/doc/screenshots/bootstrap/readme/37_example.png "Example 37")
![Example 40](demo/doc/screenshots/bootstrap/readme/40_example.png "Example 40")
```erb
<%= bootstrap_form_for(@user, layout: :horizontal) do |f| %>
<%= f.email_field :email %>
Expand Down Expand Up @@ -1210,7 +1243,7 @@ This generates:

The form-level `layout` can be overridden per field, unless the form-level layout was `inline`:

![Example 38](demo/doc/screenshots/bootstrap/readme/38_example.png "Example 38")
![Example 41](demo/doc/screenshots/bootstrap/readme/41_example.png "Example 41")
```erb
<%= bootstrap_form_for(@user, layout: :horizontal) do |f| %>
<%= f.email_field :email %>
Expand Down Expand Up @@ -1254,7 +1287,7 @@ A form-level `layout: :inline` can't be overridden because of the way Bootstrap

The `custom` option can be used to replace the browser default styles for check boxes and radio buttons with dedicated Bootstrap styled form elements. Here's an example:

![Example 39](demo/doc/screenshots/bootstrap/readme/39_example.png "Example 39")
![Example 42](demo/doc/screenshots/bootstrap/readme/42_example.png "Example 42")
```erb
<%= bootstrap_form_for(@user) do |f| %>
<%= f.email_field :email %>
Expand Down Expand Up @@ -1290,7 +1323,7 @@ This generates:
The `floating` option can be used to enable Bootstrap 5's floating labels. This option is supported on text fields
and dropdowns. Here's an example:

![Example 40](demo/doc/screenshots/bootstrap/readme/40_example.png "Example 40")
![Example 43](demo/doc/screenshots/bootstrap/readme/43_example.png "Example 43")
```erb
<%= bootstrap_form_for(@user) do |f| %>
<%= f.email_field :email, floating: true %>
Expand Down Expand Up @@ -1380,7 +1413,7 @@ To display an error message with an error summary, you can use the
`alert_message` helper. This won't output anything unless a model validation
has failed.

![Example 41](demo/doc/screenshots/bootstrap/readme/41_example.png "Example 41")
![Example 44](demo/doc/screenshots/bootstrap/readme/44_example.png "Example 44")
```erb
<%= bootstrap_form_for @user_with_error do |f| %>
<%= f.alert_message "Please fix the errors below." %>
Expand All @@ -1403,7 +1436,7 @@ Which outputs:

You can turn off the error summary like this:

![Example 42](demo/doc/screenshots/bootstrap/readme/42_example.png "Example 42")
![Example 45](demo/doc/screenshots/bootstrap/readme/45_example.png "Example 45")
```erb
<%= bootstrap_form_for @user_with_error do |f| %>
<%= f.alert_message "Please fix the errors below.", error_summary: false %>
Expand All @@ -1420,7 +1453,7 @@ This generates:

To output a simple unordered list of errors, use the `error_summary` helper.

![Example 43](demo/doc/screenshots/bootstrap/readme/43_example.png "Example 43")
![Example 46](demo/doc/screenshots/bootstrap/readme/46_example.png "Example 46")
```erb
<%= bootstrap_form_for @user_with_error do |f| %>
<%= f.error_summary %>
Expand All @@ -1442,7 +1475,7 @@ Which outputs:

If you want to display a custom inline error for a specific attribute not represented by a form field, use the `errors_on` helper.

![Example 44](demo/doc/screenshots/bootstrap/readme/44_example.png "Example 44")
![Example 47](demo/doc/screenshots/bootstrap/readme/47_example.png "Example 47")
```erb
<%= bootstrap_form_for @user_with_error do |f| %>
<%= f.errors_on :email %>
Expand All @@ -1459,7 +1492,7 @@ Which outputs:

You can hide the attribute name like this:

![Example 45](demo/doc/screenshots/bootstrap/readme/45_example.png "Example 45")
![Example 48](demo/doc/screenshots/bootstrap/readme/48_example.png "Example 48")
```erb
<%= bootstrap_form_for @user_with_error do |f| %>
<%= f.errors_on :email, hide_attribute_name: true %>
Expand All @@ -1476,7 +1509,7 @@ Which outputs:

You can also use a custom class for the wrapping div, like this:

![Example 46](demo/doc/screenshots/bootstrap/readme/46_example.png "Example 46")
![Example 49](demo/doc/screenshots/bootstrap/readme/49_example.png "Example 49")
```erb
<%= bootstrap_form_for @user_with_error do |f| %>
<%= f.errors_on :email, custom_class: 'custom-error' %>
Expand Down Expand Up @@ -1511,7 +1544,7 @@ ActiveModel::Validations::PresenceValidator.

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

![Example 47](demo/doc/screenshots/bootstrap/readme/47_example.png "Example 47")
![Example 50](demo/doc/screenshots/bootstrap/readme/50_example.png "Example 50")
```erb
<%= f.password_field :login, label: "New Username", required: true %>
<%= f.password_field :password, label: "New Password", required: false %>
Expand Down
Binary file modified demo/doc/screenshots/bootstrap/readme/21_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/22_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/23_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/24_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/25_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/26_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/27_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/28_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/29_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/30_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/31_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/32_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/33_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/34_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/35_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/36_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/37_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/38_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/39_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/40_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/41_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/42_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/43_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/44_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/45_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/doc/screenshots/bootstrap/readme/46_example.png
Binary file modified demo/doc/screenshots/bootstrap/readme/47_example.png
Binary file added demo/doc/screenshots/bootstrap/readme/48_example.png
5 changes: 3 additions & 2 deletions lib/bootstrap_form/inputs/check_box.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ module CheckBox
def check_box_with_bootstrap(name, options={}, checked_value="1", unchecked_value="0", &block)
options = options.symbolize_keys!
check_box_options = options.except(:class, :label, :label_class, :error_message, :help,
:inline, :hide_label, :skip_label, :wrapper_class, :switch)
:inline, :hide_label, :skip_label, :wrapper, :wrapper_class, :switch)
check_box_options[:class] = check_box_classes(name, options)

tag.div(class: check_box_wrapper_class(options)) do
tag.div(class: check_box_wrapper_class(options), **options[:wrapper].to_h.except(:class)) do
html = check_box_without_bootstrap(name, check_box_options, checked_value, unchecked_value)
html.concat(check_box_label(name, options, checked_value, &block)) unless options[:skip_label]
html.concat(generate_error(name)) if options[:error_message]
Expand Down Expand Up @@ -68,6 +68,7 @@ def check_box_wrapper_class(options)
classes << "form-check-inline" if layout_inline?(options[:inline])
classes << "mb-3" unless options[:multiple] || layout == :horizontal
classes << "form-switch" if options[:switch]
classes << options[:wrapper][:class] if options.dig(:wrapper, :class).present?
classes << options[:wrapper_class] if options[:wrapper_class].present?
classes.flatten.compact
end
Expand Down
5 changes: 3 additions & 2 deletions lib/bootstrap_form/inputs/radio_button.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ module RadioButton
def radio_button_with_bootstrap(name, value, *args)
options = args.extract_options!.symbolize_keys!
radio_button_options = options.except(:class, :label, :label_class, :error_message, :help,
:inline, :hide_label, :skip_label, :wrapper_class)
:inline, :hide_label, :skip_label, :wrapper, :wrapper_class)

radio_button_options[:class] = radio_button_classes(name, options)

tag.div(class: radio_button_wrapper_class(options)) do
tag.div(class: radio_button_wrapper_class(options), **options[:wrapper].to_h.except(:class)) do
html = radio_button_without_bootstrap(name, value, radio_button_options)
html.concat(radio_button_label(name, value, options)) unless options[:skip_label]
html.concat(generate_error(name)) if options[:error_message]
Expand Down Expand Up @@ -51,6 +51,7 @@ def radio_button_wrapper_class(options)
classes = ["form-check"]
classes << "form-check-inline" if layout_inline?(options[:inline])
classes << "disabled" if options[:disabled]
classes << options[:wrapper][:class] if options.dig(:wrapper, :class).present?
classes << options[:wrapper_class] if options[:wrapper_class].present?
classes.flatten.compact
end
Expand Down

0 comments on commit 6739cd7

Please sign in to comment.