Skip to content

Commit 14e3d91

Browse files
committed
Uses <legend> which won't work because HTML
This commit also identified an error in existing code where `inline: true` on the collection field wasn't generating the right classes.
1 parent c07697e commit 14e3d91

File tree

13 files changed

+972
-454
lines changed

13 files changed

+972
-454
lines changed

.yarnrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
# yarn lockfile v1
33

44

5-
lastUpdateCheck 1763256402231
5+
lastUpdateCheck 1763690055251

README.md

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ This generates the following HTML:
120120
</form>
121121
```
122122

123+
Note: All examples in this README are generated with the configuration option `fieldset_around_collections` set to `true`. See the [Configuration](#configuration) section.
124+
123125
### bootstrap_form_tag
124126

125127
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:
@@ -233,6 +235,7 @@ The current configuration options are:
233235
| Option | Default value | Description |
234236
|---------------------------|------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
235237
| `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. |
238+
| `fieldset_around_collections` | false | Historically, `bootstrap_form` generated a wrapper around `collection_checkboxes` and `collection_radio_buttons` using the same `form_group` as individual controls used. This markup caused accessibility problems. Setting `fieldset_around_collections = true` will generate collections of checkboxes and radio buttons wrapper in a `<fieldset>` with the text as a `<legend>` (https://www.w3.org/WAI/tutorials/forms/grouping/). This _will_ make visible changes to pages that use the collection methods.<br/><br/>The default for this option will be changed to `true` in a future version. |
236239

237240
Example:
238241

@@ -781,8 +784,8 @@ This generates:
781784
This generates:
782785

783786
```html
784-
<div class="mb-3">
785-
<label class="form-label" for="user_skill_level">Skill level</label>
787+
<fieldset class="mb-3">
788+
<legend class="form-label">Skill level</legend>
786789
<div class="form-check">
787790
<input class="form-check-input" id="user_skill_level_1" name="user[skill_level]" type="radio" value="1">
788791
<label class="form-check-label" for="user_skill_level_1">Mind reading</label>
@@ -791,10 +794,10 @@ This generates:
791794
<input class="form-check-input" id="user_skill_level_2" name="user[skill_level]" type="radio" value="2">
792795
<label class="form-check-label" for="user_skill_level_2">Farming</label>
793796
</div>
794-
</div>
797+
</fieldset>
795798
<input id="user_skills" name="user[skills][]" type="hidden" value="">
796-
<div class="mb-3">
797-
<label class="form-label" for="user_skills">Skills</label>
799+
<fieldset class="mb-3">
800+
<legend class="form-label">Skills</legend>
798801
<div class="form-check">
799802
<input class="form-check-input" id="user_skills_1" name="user[skills][]" type="checkbox" value="1">
800803
<label class="form-check-label" for="user_skills_1">Mind reading</label>
@@ -803,7 +806,7 @@ This generates:
803806
<input class="form-check-input" id="user_skills_2" name="user[skills][]" type="checkbox" value="2">
804807
<label class="form-check-label" for="user_skills_2">Farming</label>
805808
</div>
806-
</div>
809+
</fieldset>
807810
```
808811

809812
NOTE: These helpers do not currently support a block, unlike their equivalent Rails helpers. See issue [#477](https://github.com/bootstrap-ruby/bootstrap_form/issues/477). If you need to use the block syntax, use `collection_check_boxes_without_bootstrap` or `collection_radio_buttons_without_bootstrap` for now.
@@ -829,8 +832,8 @@ To add `data-` attributes to a collection of radio buttons, map your models to a
829832
This generates:
830833

831834
```html
832-
<div class="mb-3">
833-
<label class="form-label" for="user_misc">Misc</label>
835+
<fieldset class="mb-3">
836+
<legend class="form-label">Misc</legend>
834837
<div class="form-check">
835838
<input class="form-check-input" id="user_misc_1" name="user[misc]" type="radio" value="1">
836839
<label class="form-check-label" for="user_misc_1">Foo</label>
@@ -839,7 +842,7 @@ This generates:
839842
<input class="form-check-input" id="user_misc_2" name="user[misc]" type="radio" value="2">
840843
<label class="form-check-label" for="user_misc_2">Bar</label>
841844
</div>
842-
</div>
845+
</fieldset>
843846
```
844847

845848
## Range Controls
@@ -1417,7 +1420,7 @@ This generates:
14171420
</form>
14181421
```
14191422

1420-
A form-level `layout: :inline` can't be overridden because of the way Bootstrap 4 implements in-line layouts. One possible work-around is to leave the form-level layout as default, and specify the individual fields as `layout: :inline`, except for the fields(s) that should be other than in-line.
1423+
A form-level `layout: :inline` can't be overridden because of the way Bootstrap implements in-line layouts. One possible work-around is to leave the form-level layout as default, and specify the individual fields as `layout: :inline`, except for the fields(s) that should be other than in-line.
14211424

14221425
### Floating Labels
14231426

@@ -1493,8 +1496,8 @@ Generated HTML:
14931496
<input class="form-control is-invalid" id="user_email" name="user[email]" required="required" type="email" value="steve.example.com">
14941497
<div class="invalid-feedback">is invalid</div>
14951498
</div>
1496-
<div class="mb-3">
1497-
<label class="form-label" for="user_misc">Misc</label>
1499+
<fieldset class="mb-3">
1500+
<legend class="form-label">Misc</legend>
14981501
<div class="form-check">
14991502
<input checked class="form-check-input is-invalid" id="user_misc_1" name="user[misc]" type="radio" value="1">
15001503
<label class="form-check-label" for="user_misc_1">Mind reading</label>
@@ -1504,10 +1507,10 @@ Generated HTML:
15041507
<label class="form-check-label" for="user_misc_2">Farming</label>
15051508
<div class="invalid-feedback">is invalid</div>
15061509
</div>
1507-
</div>
1510+
</fieldset>
15081511
<input id="user_preferences" name="user[preferences][]" type="hidden" value="">
1509-
<div class="mb-3">
1510-
<label class="form-label" for="user_preferences">Preferences</label>
1512+
<fieldset class="mb-3">
1513+
<legend class="form-label">Preferences</legend>
15111514
<div class="form-check">
15121515
<input checked class="form-check-input is-invalid" id="user_preferences_1" name="user[preferences][]" type="checkbox" value="1">
15131516
<label class="form-check-label" for="user_preferences_1">Good</label>
@@ -1517,7 +1520,7 @@ Generated HTML:
15171520
<label class="form-check-label" for="user_preferences_2">Bad</label>
15181521
<div class="invalid-feedback">is invalid</div>
15191522
</div>
1520-
</div>
1523+
</fieldset>
15211524
<div class="mb-3">
15221525
<label class="form-label" for="user_address_attributes_street">Street</label>
15231526
<input class="form-control is-invalid" id="user_address_attributes_street" name="user[address_attributes][street]" type="text" value="Bar">
1.02 KB
Loading
452 Bytes
Loading
1.01 KB
Loading
452 Bytes
Loading
1.34 KB
Loading

demo/test/system/bootstrap_test.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@
44
require "capybara_screenshot_diff/minitest"
55

66
class BootstrapTest < ApplicationSystemTestCase
7-
setup { screenshot_section :bootstrap }
7+
setup do
8+
screenshot_section :bootstrap
9+
Rails.application.config.bootstrap_form.fieldset_around_collections = true
10+
end
11+
12+
teardown do
13+
Rails.application.config.bootstrap_form.fieldset_around_collections = false
14+
end
815

916
test "visiting the index" do
1017
screenshot_group :index

lib/bootstrap_form/components/labels.rb

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,8 @@ module Labels
1010
def generate_label(id, name, options, custom_label_col, group_layout)
1111
return if options.blank?
1212

13-
# id is the caller's options[:id] at the only place this method is called.
14-
# The options argument is a small subset of the options that might have
15-
# been passed to generate_label's caller, and definitely doesn't include
16-
# :id.
17-
options[:for] = id if acts_like_form_tag
18-
19-
options[:class] = label_classes(name, options, custom_label_col, group_layout)
20-
options.delete(:class) if options[:class].none?
21-
22-
label(name, label_text(name, options), options.except(:text))
13+
prepare_label_options(id, name, options, custom_label_col, group_layout)
14+
label(name, label_text(name, options[:text]), options.except(:text))
2315
end
2416

2517
def label_classes(name, options, custom_label_col, group_layout)
@@ -42,14 +34,25 @@ def label_layout_classes(custom_label_col, group_layout)
4234
end
4335
end
4436

45-
def label_text(name, options)
46-
label = options[:text] || object&.class&.try(:human_attribute_name, name)&.html_safe # rubocop:disable Rails/OutputSafety, Style/SafeNavigationChainLength
37+
def label_text(name, text)
38+
label = text || object&.class&.try(:human_attribute_name, name)&.html_safe # rubocop:disable Rails/OutputSafety, Style/SafeNavigationChainLength
4739
if label_errors && error?(name)
4840
(" ".html_safe + get_error_messages(name)).prepend(label)
4941
else
5042
label
5143
end
5244
end
45+
46+
def prepare_label_options(id, name, options, custom_label_col, group_layout)
47+
# id is the caller's options[:id] at the only place this method is called.
48+
# The options argument is a small subset of the options that might have
49+
# been passed to generate_label's caller, and definitely doesn't include
50+
# :id.
51+
options[:for] = id if acts_like_form_tag
52+
53+
options[:class] = label_classes(name, options, custom_label_col, group_layout)
54+
options.delete(:class) if options[:class].none?
55+
end
5356
end
5457
end
5558
end

lib/bootstrap_form/engine.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ class Engine < Rails::Engine
99

1010
config.bootstrap_form = BootstrapForm.config
1111
config.bootstrap_form.default_form_attributes ||= {}
12+
if config.bootstrap_form.fieldset_around_collections.nil?
13+
config.bootstrap_form.fieldset_around_collections = Rails.env.development?
14+
end
1215

1316
initializer "bootstrap_form.configure" do |app|
1417
BootstrapForm.config = app.config.bootstrap_form

0 commit comments

Comments
 (0)