bootstrap_form 5.4.0 → 5.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer.json +38 -0
  3. data/.github/workflows/ruby.yml +19 -7
  4. data/.gitignore +21 -7
  5. data/.rubocop.yml +25 -15
  6. data/CHANGELOG.md +3 -0
  7. data/CONTRIBUTING.md +53 -111
  8. data/DOCKER.md +95 -0
  9. data/Gemfile +7 -1
  10. data/README.md +166 -100
  11. data/RELEASING.md +4 -10
  12. data/Rakefile +34 -16
  13. data/bootstrap_form.gemspec +1 -1
  14. data/compose.yml +36 -0
  15. data/gemfiles/7.2.gemfile +10 -0
  16. data/gemfiles/8.0.gemfile +10 -0
  17. data/gemfiles/8.1.gemfile +9 -0
  18. data/gemfiles/common.gemfile +10 -9
  19. data/gemfiles/edge.gemfile +5 -1
  20. data/lib/bootstrap_form/action_view_extensions/form_helper.rb +6 -6
  21. data/lib/bootstrap_form/components/labels.rb +17 -13
  22. data/lib/bootstrap_form/components/validation.rb +6 -3
  23. data/lib/bootstrap_form/configuration.rb +17 -2
  24. data/lib/bootstrap_form/engine.rb +12 -0
  25. data/lib/bootstrap_form/form_builder.rb +14 -6
  26. data/lib/bootstrap_form/form_group.rb +4 -4
  27. data/lib/bootstrap_form/form_group_builder.rb +17 -8
  28. data/lib/bootstrap_form/helpers/bootstrap.rb +15 -9
  29. data/lib/bootstrap_form/helpers/field.rb +2 -0
  30. data/lib/bootstrap_form/inputs/base.rb +11 -6
  31. data/lib/bootstrap_form/inputs/check_box.rb +13 -6
  32. data/lib/bootstrap_form/inputs/collection_check_boxes.rb +3 -8
  33. data/lib/bootstrap_form/inputs/collection_radio_buttons.rb +1 -0
  34. data/lib/bootstrap_form/inputs/file_field.rb +1 -1
  35. data/lib/bootstrap_form/inputs/inputs_collection.rb +67 -11
  36. data/lib/bootstrap_form/inputs/radio_button.rb +2 -1
  37. data/lib/bootstrap_form/inputs/range_field.rb +1 -1
  38. data/lib/bootstrap_form/inputs/rich_text_area.rb +2 -0
  39. data/lib/bootstrap_form/inputs/submit.rb +3 -1
  40. data/lib/bootstrap_form/inputs/text_area.rb +2 -0
  41. data/lib/bootstrap_form/inputs/time_zone_select.rb +1 -1
  42. data/lib/bootstrap_form/version.rb +4 -2
  43. data/lib/bootstrap_form.rb +4 -15
  44. metadata +17 -18
  45. data/.yarnrc +0 -5
  46. data/Dockerfile +0 -22
  47. data/docker-compose-system-test.yml +0 -45
  48. data/docker-compose.yml +0 -29
  49. data/gemfiles/6.1.gemfile +0 -4
  50. data/gemfiles/7.0.gemfile +0 -5
  51. data/gemfiles/7.1.gemfile +0 -5
data/README.md CHANGED
@@ -25,43 +25,64 @@ Some other nice things that `bootstrap_form` does for you are:
25
25
 
26
26
  `bootstrap_form` supports at a minimum the currently supported versions of Ruby and Rails:
27
27
 
28
- * Ruby 3.0+ (https://www.ruby-lang.org/en/downloads/branches/)
29
- * Rails 6.1+ (https://guides.rubyonrails.org/maintenance_policy.html)
28
+ * Ruby 3.2+ (https://www.ruby-lang.org/en/downloads/branches/)
29
+ * Rails 7.2+ (https://guides.rubyonrails.org/maintenance_policy.html)
30
30
  * Bootstrap 5.0+
31
31
 
32
32
  ## Installation
33
33
 
34
- 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`:
34
+ This gem needs Bootstrap. The gem itself doesn't really care how Bootstrap is included in your application. There are many ways to install Bootstrap in a Rails application. Covering them all is beyond the scope of this README. However, here are some hints for a couple of common options.
35
35
 
36
- ```ruby
37
- gem "bootstrap", "~> 5.0"
36
+ If you're creating a new Rails app, create it with at least the following options:
37
+
38
+ ```bash
39
+ rails new --javascript=esbuild --css=bootstrap <application-name>
38
40
  ```
39
41
 
40
- And follow the remaining instructions in the [official bootstrap installation guide](https://github.com/twbs/bootstrap-rubygem#a-ruby-on-rails) for setting up `application.scss` and `application.js`.
42
+ `esbuild` can be any of the options, _except_ the default `importmaps`.
41
43
 
42
- Add the `bootstrap_form` gem to your `Gemfile`:
44
+ If you have an existing project, and it's processing CSS and JavaScript with some sort of front-end preprocessor, then install Bootstrap for your front-end preprocessor. That's probably something like this:
45
+
46
+ ```bash
47
+ yarn add bootstrap popper.js
48
+ ```
49
+
50
+ You can use this gem with other ways of installing Bootstrap, but how to do so is outside the scope of this README.
51
+
52
+ Once Bootstrap is installed, add the `bootstrap_form` gem to your `Gemfile`:
43
53
 
44
54
  ```ruby
45
- gem "bootstrap_form", "~> 5.4"
55
+ gem "bootstrap_form", "~> 5.6"
46
56
  ```
47
57
 
48
58
  Then:
49
59
 
50
60
  `bundle install`
51
61
 
52
- Depending on which CSS pre-processor you are using, adding the bootstrap form styles differs slightly.
53
- 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:
62
+ `bootstrap_form` uses a very small number of its own CSS styles. These styles are used in HTML generated by the `error_summary` and `alert_message` error helpers, and the `date_select`, `time_select`, and `datetime_select` helpers. If you're not using those helpers, you don't need to install the `bootstrap_form` CSS styles.
54
63
 
55
- ```css
56
- *= require rails_bootstrap_forms
64
+ If you do need the CSS styles, add them to your CSS bundle (usually your `application.scss` file). The way to do this depends on whether you're using Propshaft (the Rails 8 default), or Sprockets (pre-Rails 8). (Check your `Gemfile` to see whether you're using `sprockets-rails` or `propshaft`.)
65
+
66
+ If you're using Propshaft, add the styles to your CSS bundle like this:
67
+
68
+ ```scss
69
+ @use "rails_bootstrap_forms";
57
70
  ```
58
71
 
59
- If you followed the [official bootstrap installation guide](https://github.com/twbs/bootstrap-rubygem#a-ruby-on-rails), you'll probably have switched to SCSS. In this case add the following line to your `application.scss`:
72
+ If you're using Sprockets, add the styles to your CSS bundle like this:
60
73
 
61
74
  ```scss
62
- @import "rails_bootstrap_forms";
75
+ @import "rails_bootstrap_forms.css";
76
+ ```
77
+
78
+ If you're using Sprockets, you can also consider using the `bootstrap` gem to your `Gemfile`, as a way of installing Bootstrap itself. However, we haven't used this approach for a few years. Please report an issue if it doesn't work:
79
+
80
+ ```ruby
81
+ gem "bootstrap", "~> 5.0"
63
82
  ```
64
83
 
84
+ And follow the remaining instructions in the [official bootstrap installation guide](https://github.com/twbs/bootstrap-rubygem#a-ruby-on-rails) for setting up `application.scss` and `application.js`.
85
+
65
86
  ## Usage
66
87
 
67
88
  ### bootstrap_form_for
@@ -91,7 +112,7 @@ This generates the following HTML:
91
112
  <input class="form-control" id="user_password" name="user[password]" type="password">
92
113
  </div>
93
114
  <div class="form-check mb-3">
94
- <input autocomplete="off" name="user[remember_me]" type="hidden" value="0">
115
+ <input name="user[remember_me]" type="hidden" value="0">
95
116
  <input class="form-check-input" id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
96
117
  <label class="form-check-label" for="user_remember_me">Remember me</label>
97
118
  </div>
@@ -99,6 +120,8 @@ This generates the following HTML:
99
120
  </form>
100
121
  ```
101
122
 
123
+ Note: All examples in this README are generated with the configuration option `group_around_collections` set to `true`. See the [Configuration](#configuration) section.
124
+
102
125
  ### bootstrap_form_tag
103
126
 
104
127
  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:
@@ -151,7 +174,7 @@ This generates:
151
174
  <small class="form-text text-muted">A good password should be at least six characters long</small>
152
175
  </div>
153
176
  <div class="form-check mb-3">
154
- <input autocomplete="off" name="user[remember_me]" type="hidden" value="0">
177
+ <input name="user[remember_me]" type="hidden" value="0">
155
178
  <input class="form-check-input" id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
156
179
  <label class="form-check-label" for="user_remember_me">Remember me</label>
157
180
  </div>
@@ -205,13 +228,14 @@ Generated HTML:
205
228
 
206
229
  ## Configuration
207
230
 
208
- `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.
231
+ `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, or for enabling or disabling new functionality that might not be compatible with your application.
209
232
 
210
233
  The current configuration options are:
211
234
 
212
235
  | Option | Default value | Description |
213
236
  |---------------------------|------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
214
- | `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. |
237
+ | `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
+ | `group_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 `group_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. |
215
239
 
216
240
  Example:
217
241
 
@@ -529,11 +553,25 @@ It's just a short form of `wrapper: { class: 'mb-3 additional-class' }`.
529
553
 
530
554
  If you don't want any class on the form group div, you can set it to `false`: `wrapper_class: false`.
531
555
 
556
+ ![Example 16](demo/doc/screenshots/bootstrap/readme/16_example.png "Example 16")
557
+ ```erb
558
+ <%= f.text_field :name, wrapper: { class: false } %>
559
+ ```
560
+
561
+ This generates:
562
+
563
+ ```html
564
+ <div>
565
+ <label class="form-label" for="user_name">Name</label>
566
+ <input class="form-control" id="user_name" name="user[name]" type="text">
567
+ </div>
568
+ ```
569
+
532
570
  ### Suppressing the Form Group Altogether
533
571
 
534
572
  You may want to define your own form group div around a field. To do so, add the option `wrapper: false` to the input field. For example:
535
573
 
536
- ![Example 16](demo/doc/screenshots/bootstrap/readme/16_example.png "Example 16")
574
+ ![Example 17](demo/doc/screenshots/bootstrap/readme/17_example.png "Example 17")
537
575
  ```erb
538
576
  <%= f.form_group :user do %>
539
577
  <%= f.email_field :email, wrapper: false %>
@@ -554,7 +592,7 @@ Note that Bootstrap relies on the form group div to correctly format most fields
554
592
 
555
593
  Our select helper accepts the same arguments as the [default Rails helper](http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-select). Here's an example of how you pass both options and html_options hashes:
556
594
 
557
- ![Example 17](demo/doc/screenshots/bootstrap/readme/17_example.png "Example 17")
595
+ ![Example 18](demo/doc/screenshots/bootstrap/readme/18_example.png "Example 18")
558
596
  ```erb
559
597
  <%= f.select :product, [["Apple", 1], ["Grape", 2]], { label: "Choose your favorite fruit:", wrapper: { class: 'has-warning', data: { foo: 'bar' } } }, { class: "selectpicker" } %>
560
598
  ```
@@ -577,7 +615,7 @@ Checkboxes and radios should be placed inside of a `form_group` to render
577
615
  properly. The following example ensures that the entire form group will display
578
616
  an error if an associated validations fails:
579
617
 
580
- ![Example 18](demo/doc/screenshots/bootstrap/readme/18_example.png "Example 18")
618
+ ![Example 19](demo/doc/screenshots/bootstrap/readme/19_example.png "Example 19")
581
619
  ```erb
582
620
  <%= f.form_group :skill_level, label: { text: "Skill" }, help: "Optional Help Text" do %>
583
621
  <%= f.radio_button :skill_level, 0, label: "Novice", checked: true %>
@@ -611,7 +649,7 @@ This generates:
611
649
  </div>
612
650
  <div class="mb-3">
613
651
  <div class="form-check mb-3">
614
- <input autocomplete="off" name="user[terms]" type="hidden" value="0">
652
+ <input name="user[terms]" type="hidden" value="0">
615
653
  <input class="form-check-input" id="user_terms" name="user[terms]" type="checkbox" value="1">
616
654
  <label class="form-check-label" for="user_terms">I agree to the Terms of Service</label>
617
655
  </div>
@@ -620,7 +658,7 @@ This generates:
620
658
 
621
659
  You can also create a checkbox using a block:
622
660
 
623
- ![Example 19](demo/doc/screenshots/bootstrap/readme/19_example.png "Example 19")
661
+ ![Example 20](demo/doc/screenshots/bootstrap/readme/20_example.png "Example 20")
624
662
  ```erb
625
663
  <%= f.form_group :terms, label: { text: "Optional Label" } do %>
626
664
  <%= f.check_box :terms do %>
@@ -635,7 +673,7 @@ This generates:
635
673
  <div class="mb-3">
636
674
  <label class="form-label" for="user_terms">Optional Label</label>
637
675
  <div class="form-check mb-3">
638
- <input autocomplete="off" name="user[terms]" type="hidden" value="0">
676
+ <input name="user[terms]" type="hidden" value="0">
639
677
  <input class="form-check-input" id="user_terms" name="user[terms]" type="checkbox" value="1">
640
678
  <label class="form-check-label" for="user_terms">
641
679
  You need to check this box to accept our terms of service and privacy policy
@@ -646,7 +684,7 @@ This generates:
646
684
 
647
685
  To display checkboxes and radios inline, pass the `inline: true` option:
648
686
 
649
- ![Example 20](demo/doc/screenshots/bootstrap/readme/20_example.png "Example 20")
687
+ ![Example 21](demo/doc/screenshots/bootstrap/readme/21_example.png "Example 21")
650
688
  ```erb
651
689
  <%= f.form_group :skill_level, label: { text: "Skill" } do %>
652
690
  <%= f.radio_button :skill_level, 0, label: "Novice", inline: true %>
@@ -677,7 +715,7 @@ This generates:
677
715
 
678
716
  Check boxes and radio buttons are wrapped in a `div.form-check`. You can add classes to this `div` with the `:wrapper_class` option:
679
717
 
680
- ![Example 21](demo/doc/screenshots/bootstrap/readme/21_example.png "Example 21")
718
+ ![Example 22](demo/doc/screenshots/bootstrap/readme/22_example.png "Example 22")
681
719
  ```erb
682
720
  <%= f.radio_button :skill_level, 0, label: "Novice", inline: true, wrapper_class: "w-auto" %>
683
721
  ```
@@ -693,7 +731,7 @@ This generates:
693
731
 
694
732
  You can also add a style to the tag using the `wrapper` option:
695
733
 
696
- ![Example 22](demo/doc/screenshots/bootstrap/readme/22_example.png "Example 22")
734
+ ![Example 23](demo/doc/screenshots/bootstrap/readme/23_example.png "Example 23")
697
735
  ```erb
698
736
  <%= f.check_box :skilled, inline: true, wrapper: {style: "color: green"} %>
699
737
  <%= f.radio_button :skill_level, 0, label: "Novice", inline: true, wrapper: {class: 'w-auto', style: "color: red"} %>
@@ -703,7 +741,7 @@ This generates:
703
741
 
704
742
  ```html
705
743
  <div class="form-check form-check-inline mb-3" style="color: green">
706
- <input autocomplete="off" name="user[skilled]" type="hidden" value="0">
744
+ <input name="user[skilled]" type="hidden" value="0">
707
745
  <input class="form-check-input" id="user_skilled" name="user[skilled]" type="checkbox" value="1">
708
746
  <label class="form-check-label" for="user_skilled">Skilled</label>
709
747
  </div>
@@ -717,7 +755,7 @@ This generates:
717
755
 
718
756
  To render checkboxes as switches with Bootstrap 4.2+, use `switch: true`:
719
757
 
720
- ![Example 23](demo/doc/screenshots/bootstrap/readme/23_example.png "Example 23")
758
+ ![Example 24](demo/doc/screenshots/bootstrap/readme/24_example.png "Example 24")
721
759
  ```erb
722
760
  <%= f.check_box :remember_me, switch: true %>
723
761
  ```
@@ -726,7 +764,7 @@ This generates:
726
764
 
727
765
  ```html
728
766
  <div class="form-check mb-3 form-switch">
729
- <input autocomplete="off" name="user[remember_me]" type="hidden" value="0">
767
+ <input name="user[remember_me]" type="hidden" value="0">
730
768
  <input class="form-check-input" id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
731
769
  <label class="form-check-label" for="user_remember_me">Remember me</label>
732
770
  </div>
@@ -737,7 +775,7 @@ This generates:
737
775
  `bootstrap_form` also provides helpers that automatically create the
738
776
  `form_group` and the `radio_button`s or `check_box`es for you:
739
777
 
740
- ![Example 24](demo/doc/screenshots/bootstrap/readme/24_example.png "Example 24")
778
+ ![Example 25](demo/doc/screenshots/bootstrap/readme/25_example.png "Example 25")
741
779
  ```erb
742
780
  <%= f.collection_radio_buttons :skill_level, Skill.all, :id, :name %>
743
781
  <%= f.collection_check_boxes :skills, Skill.all, :id, :name %>
@@ -746,8 +784,8 @@ This generates:
746
784
  This generates:
747
785
 
748
786
  ```html
749
- <div class="mb-3">
750
- <label class="form-label" for="user_skill_level">Skill level</label>
787
+ <div aria-labelledby="user_skill_level" class="mb-3" role="group">
788
+ <div class="form-label" id="user_skill_level">Skill level</div>
751
789
  <div class="form-check">
752
790
  <input class="form-check-input" id="user_skill_level_1" name="user[skill_level]" type="radio" value="1">
753
791
  <label class="form-check-label" for="user_skill_level_1">Mind reading</label>
@@ -757,9 +795,9 @@ This generates:
757
795
  <label class="form-check-label" for="user_skill_level_2">Farming</label>
758
796
  </div>
759
797
  </div>
760
- <input autocomplete="off" id="user_skills" name="user[skills][]" type="hidden" value="">
761
- <div class="mb-3">
762
- <label class="form-label" for="user_skills">Skills</label>
798
+ <input id="user_skills" name="user[skills][]" type="hidden" value="">
799
+ <div aria-labelledby="user_skills" class="mb-3" role="group">
800
+ <div class="form-label" id="user_skills">Skills</div>
763
801
  <div class="form-check">
764
802
  <input class="form-check-input" id="user_skills_1" name="user[skills][]" type="checkbox" value="1">
765
803
  <label class="form-check-label" for="user_skills_1">Mind reading</label>
@@ -783,7 +821,7 @@ Collection methods accept these options:
783
821
 
784
822
  To add `data-` attributes to a collection of radio buttons, map your models to an array and add a hash:
785
823
 
786
- ![Example 25](demo/doc/screenshots/bootstrap/readme/25_example.png "Example 25")
824
+ ![Example 26](demo/doc/screenshots/bootstrap/readme/26_example.png "Example 26")
787
825
  ```erb
788
826
  <%# Use the :first and :second elements of the array to be the value and label respectively %>
789
827
  <%- choices = @collection.map { |addr| [ addr.id, addr.street, { 'data-zip-code': addr.zip_code } ] } -%>
@@ -794,8 +832,8 @@ To add `data-` attributes to a collection of radio buttons, map your models to a
794
832
  This generates:
795
833
 
796
834
  ```html
797
- <div class="mb-3">
798
- <label class="form-label" for="user_misc">Misc</label>
835
+ <div aria-labelledby="user_misc" class="mb-3" role="group">
836
+ <div class="form-label" id="user_misc">Misc</div>
799
837
  <div class="form-check">
800
838
  <input class="form-check-input" id="user_misc_1" name="user[misc]" type="radio" value="1">
801
839
  <label class="form-check-label" for="user_misc_1">Foo</label>
@@ -811,7 +849,7 @@ This generates:
811
849
 
812
850
  You can create a range control like this:
813
851
 
814
- ![Example 26](demo/doc/screenshots/bootstrap/readme/26_example.png "Example 26")
852
+ ![Example 27](demo/doc/screenshots/bootstrap/readme/27_example.png "Example 27")
815
853
  ```erb
816
854
  <%= f.range_field :excellence %>
817
855
  ```
@@ -829,7 +867,7 @@ This generates:
829
867
 
830
868
  You can create a static control like this:
831
869
 
832
- ![Example 27](demo/doc/screenshots/bootstrap/readme/27_example.png "Example 27")
870
+ ![Example 28](demo/doc/screenshots/bootstrap/readme/28_example.png "Example 28")
833
871
  ```erb
834
872
  <%= f.static_control :email %>
835
873
  ```
@@ -845,7 +883,7 @@ This generates:
845
883
 
846
884
  Here's the output for a horizontal layout:
847
885
 
848
- ![Example 28](demo/doc/screenshots/bootstrap/readme/28_example.png "Example 28")
886
+ ![Example 29](demo/doc/screenshots/bootstrap/readme/29_example.png "Example 29")
849
887
  ```erb
850
888
  <%= bootstrap_form_for(@user, layout: :horizontal) do |f| %>
851
889
  <%= f.static_control :email %>
@@ -867,7 +905,7 @@ This generates:
867
905
 
868
906
  You can also create a static control that isn't based on a model attribute:
869
907
 
870
- ![Example 29](demo/doc/screenshots/bootstrap/readme/29_example.png "Example 29")
908
+ ![Example 30](demo/doc/screenshots/bootstrap/readme/30_example.png "Example 30")
871
909
  ```erb
872
910
  <%= f.static_control :field_name, label: "Custom Static Control", value: "Content Here" %>
873
911
  ```
@@ -885,7 +923,7 @@ This generates:
885
923
 
886
924
  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:
887
925
 
888
- ![Example 30](demo/doc/screenshots/bootstrap/readme/30_example.png "Example 30")
926
+ ![Example 31](demo/doc/screenshots/bootstrap/readme/31_example.png "Example 31")
889
927
  ```erb
890
928
  <%= f.static_control label: "Custom Static Control", value: "Content Here", name: nil %>
891
929
  ```
@@ -906,7 +944,25 @@ The value of the block would be used for the content of the static "control".
906
944
  Bootstrap 4 actually creates and styles a disabled input field for static controls, so the value of the control has to be specified by the `value:` option.
907
945
  Passing a block to `static_control` no longer has any effect.
908
946
 
909
- ## Date Helpers
947
+ ## Date and Time Helpers
948
+
949
+ You can create a date picker, time picker, or date-time picker with `date_field`, `time_field`, or `datetime_field`, like this:
950
+
951
+ ![Example 32](demo/doc/screenshots/bootstrap/readme/32_example.png "Example 32")
952
+ ```erb
953
+ <%= f.date_field :joined_at, class: "w-auto" %>
954
+ ```
955
+
956
+ This generates:
957
+
958
+ ```html
959
+ <div class="mb-3">
960
+ <label class="form-label" for="user_joined_at">Joined at</label>
961
+ <input class="form-control w-auto" id="user_joined_at" name="user[joined_at]" type="date">
962
+ </div>
963
+ ```
964
+
965
+ For backwards compatibility, there are also helpers for `date_select`, `time_select`, and `datetime_select`.
910
966
 
911
967
  The multiple selects that the date and time helpers (`date_select`,
912
968
  `time_select`, `datetime_select`) generate are wrapped inside a
@@ -919,7 +975,7 @@ this by defining these selects as `inline-block` and a width of `auto`.
919
975
  The `btn btn-secondary` CSS classes are automatically added to your submit
920
976
  buttons.
921
977
 
922
- ![Example 31](demo/doc/screenshots/bootstrap/readme/31_example.png "Example 31")
978
+ ![Example 33](demo/doc/screenshots/bootstrap/readme/33_example.png "Example 33")
923
979
  ```erb
924
980
  <%= f.submit %>
925
981
  ```
@@ -933,7 +989,7 @@ This generates:
933
989
  You can also use the `primary` helper, which adds `btn btn-primary` to your
934
990
  submit button:
935
991
 
936
- ![Example 32](demo/doc/screenshots/bootstrap/readme/32_example.png "Example 32")
992
+ ![Example 34](demo/doc/screenshots/bootstrap/readme/34_example.png "Example 34")
937
993
  ```erb
938
994
  <%= f.primary "Optional Label" %>
939
995
  ```
@@ -946,7 +1002,7 @@ This generates:
946
1002
 
947
1003
  You can specify your own classes like this:
948
1004
 
949
- ![Example 33](demo/doc/screenshots/bootstrap/readme/33_example.png "Example 33")
1005
+ ![Example 35](demo/doc/screenshots/bootstrap/readme/35_example.png "Example 35")
950
1006
  ```erb
951
1007
  <%= f.submit "Log In", class: "btn btn-success" %>
952
1008
  ```
@@ -962,7 +1018,7 @@ it will be rendered as an HTML button, instead of an input tag. This allows you
962
1018
  to specify HTML content and styling for your buttons (such as adding
963
1019
  illustrative icons to them). For example, the following statements
964
1020
 
965
- ![Example 34](demo/doc/screenshots/bootstrap/readme/34_example.png "Example 34")
1021
+ ![Example 36](demo/doc/screenshots/bootstrap/readme/36_example.png "Example 36")
966
1022
  ```erb
967
1023
  <%= f.primary "Save changes <span class='bi bi-save'></span>".html_safe, render_as_button: true %>
968
1024
 
@@ -996,7 +1052,7 @@ Bootstrap classes), or for element targeting via CSS classes.
996
1052
  Be aware, however, that using the `class` option will discard any extra classes
997
1053
  you add. As an example, the following button declarations
998
1054
 
999
- ![Example 35](demo/doc/screenshots/bootstrap/readme/35_example.png "Example 35")
1055
+ ![Example 37](demo/doc/screenshots/bootstrap/readme/37_example.png "Example 37")
1000
1056
  ```erb
1001
1057
  <%= f.primary "My Nice Button", extra_class: 'my-button' %>
1002
1058
 
@@ -1014,7 +1070,7 @@ will be rendered as
1014
1070
 
1015
1071
  ## Rich Text Areas AKA Trix Editor
1016
1072
 
1017
- ![Example 36](demo/doc/screenshots/bootstrap/readme/36_example.png "Example 36")
1073
+ ![Example 38](demo/doc/screenshots/bootstrap/readme/38_example.png "Example 38")
1018
1074
  ```erb
1019
1075
  <%= f.rich_text_area(:life_story) %>
1020
1076
  ```
@@ -1024,7 +1080,7 @@ will be rendered as:
1024
1080
  ```html
1025
1081
  <div class="mb-3">
1026
1082
  <label class="form-label" for="user_life_story">Life story</label>
1027
- <input autocomplete="off" id="user_life_story_trix_input_user" name="user[life_story]" type="hidden">
1083
+ <input id="user_life_story_trix_input_user" name="user[life_story]" type="hidden">
1028
1084
  <trix-toolbar id="trix-toolbar-1">
1029
1085
  <div class="trix-button-row">
1030
1086
  <span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools">
@@ -1064,7 +1120,7 @@ will be rendered as:
1064
1120
  </div>
1065
1121
  </div>
1066
1122
  </trix-toolbar>
1067
- <trix-editor aria-label="Life story" class="trix-content form-control" contenteditable="" data-blob-url-template="http://shell:3001/rails/active_storage/blobs/redirect/:signed_id/:filename" data-direct-upload-url="http://shell:3001/rails/active_storage/direct_uploads" id="user_life_story" input="user_life_story_trix_input_user" role="textbox" toolbar="trix-toolbar-1" trix-id="1">
1123
+ <trix-editor aria-label="Life story" class="trix-content form-control" contenteditable="" data-blob-url-template="http://test.host/rails/active_storage/blobs/redirect/:signed_id/:filename" data-direct-upload-url="http://test.host/rails/active_storage/direct_uploads" id="user_life_story" input="user_life_story_trix_input_user" role="textbox" toolbar="trix-toolbar-1" trix-id="1">
1068
1124
  </trix-editor>
1069
1125
  </div>
1070
1126
  ```
@@ -1082,7 +1138,7 @@ The `hidden_field` helper in `bootstrap_form` calls the Rails helper directly, a
1082
1138
  If you want to use the original Rails form helpers for a particular field,
1083
1139
  append `_without_bootstrap` to the helper:
1084
1140
 
1085
- ![Example 37](demo/doc/screenshots/bootstrap/readme/37_example.png "Example 37")
1141
+ ![Example 39](demo/doc/screenshots/bootstrap/readme/39_example.png "Example 39")
1086
1142
  ```erb
1087
1143
  <%= f.text_field_without_bootstrap :email %>
1088
1144
  ```
@@ -1104,7 +1160,7 @@ To use an inline-layout form, use the `layout: :inline` option. To hide labels,
1104
1160
  use the `hide_label: true` option, which keeps your labels accessible to those
1105
1161
  using screen readers.
1106
1162
 
1107
- ![Example 38](demo/doc/screenshots/bootstrap/readme/38_example.png "Example 38")
1163
+ ![Example 40](demo/doc/screenshots/bootstrap/readme/40_example.png "Example 40")
1108
1164
  ```erb
1109
1165
  <%= bootstrap_form_for(@user, layout: :inline) do |f| %>
1110
1166
  <%= f.email_field :email, hide_label: true %>
@@ -1128,7 +1184,7 @@ This generates:
1128
1184
  </div>
1129
1185
  <div class="col">
1130
1186
  <div class="form-check form-check-inline">
1131
- <input autocomplete="off" name="user[remember_me]" type="hidden" value="0">
1187
+ <input name="user[remember_me]" type="hidden" value="0">
1132
1188
  <input class="form-check-input" id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
1133
1189
  <label class="form-check-label" for="user_remember_me">Remember me</label>
1134
1190
  </div>
@@ -1141,7 +1197,7 @@ This generates:
1141
1197
 
1142
1198
  To skip label rendering at all, use `skip_label: true` option.
1143
1199
 
1144
- ![Example 39](demo/doc/screenshots/bootstrap/readme/39_example.png "Example 39")
1200
+ ![Example 41](demo/doc/screenshots/bootstrap/readme/41_example.png "Example 41")
1145
1201
  ```erb
1146
1202
  <%= f.password_field :password, skip_label: true %>
1147
1203
  ```
@@ -1163,7 +1219,7 @@ To use a horizontal-layout form with labels to the left of the control, use the
1163
1219
  In the example below, the submit button has been wrapped in a `form_group` to
1164
1220
  keep it properly aligned.
1165
1221
 
1166
- ![Example 40](demo/doc/screenshots/bootstrap/readme/40_example.png "Example 40")
1222
+ ![Example 42](demo/doc/screenshots/bootstrap/readme/42_example.png "Example 42")
1167
1223
  ```erb
1168
1224
  <%= bootstrap_form_for(@user, layout: :horizontal, label_col: "col-sm-2", control_col: "col-sm-10") do |f| %>
1169
1225
  <%= f.email_field :email %>
@@ -1194,7 +1250,7 @@ This generates:
1194
1250
  <div class="mb-3 row">
1195
1251
  <div class="col-sm-10 offset-sm-2">
1196
1252
  <div class="form-check">
1197
- <input autocomplete="off" name="user[remember_me]" type="hidden" value="0">
1253
+ <input name="user[remember_me]" type="hidden" value="0">
1198
1254
  <input class="form-check-input" id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
1199
1255
  <label class="form-check-label" for="user_remember_me">Remember me</label>
1200
1256
  </div>
@@ -1210,7 +1266,7 @@ This generates:
1210
1266
 
1211
1267
  The `label_col` and `control_col` css classes can also be changed per control:
1212
1268
 
1213
- ![Example 41](demo/doc/screenshots/bootstrap/readme/41_example.png "Example 41")
1269
+ ![Example 43](demo/doc/screenshots/bootstrap/readme/43_example.png "Example 43")
1214
1270
  ```erb
1215
1271
  <%= bootstrap_form_for(@user, layout: :horizontal) do |f| %>
1216
1272
  <%= f.email_field :email %>
@@ -1241,7 +1297,7 @@ This generates:
1241
1297
  <div class="mb-3 row">
1242
1298
  <div class="col-sm-10">
1243
1299
  <div class="form-check">
1244
- <input autocomplete="off" name="user[terms]" type="hidden" value="0">
1300
+ <input name="user[terms]" type="hidden" value="0">
1245
1301
  <input class="form-check-input" id="user_terms" name="user[terms]" type="checkbox" value="1">
1246
1302
  <label class="form-check-label" for="user_terms">Terms</label>
1247
1303
  </div>
@@ -1277,7 +1333,7 @@ end
1277
1333
 
1278
1334
  Control col wrapper class can be modified with `add_control_col_class`. This option will preserve column definition:
1279
1335
 
1280
- ![Example 42](demo/doc/screenshots/bootstrap/readme/42_example.png "Example 42")
1336
+ ![Example 44](demo/doc/screenshots/bootstrap/readme/44_example.png "Example 44")
1281
1337
  ```erb
1282
1338
  <%= bootstrap_form_for(@user, layout: :horizontal) do |f| %>
1283
1339
  <%= f.email_field :email %>
@@ -1316,7 +1372,7 @@ This generates:
1316
1372
 
1317
1373
  The form-level `layout` can be overridden per field, unless the form-level layout was `inline`:
1318
1374
 
1319
- ![Example 43](demo/doc/screenshots/bootstrap/readme/43_example.png "Example 43")
1375
+ ![Example 45](demo/doc/screenshots/bootstrap/readme/45_example.png "Example 45")
1320
1376
  ```erb
1321
1377
  <%= bootstrap_form_for(@user, layout: :horizontal) do |f| %>
1322
1378
  <%= f.email_field :email %>
@@ -1355,7 +1411,7 @@ This generates:
1355
1411
  </div>
1356
1412
  <div class="mb-3">
1357
1413
  <div class="form-check">
1358
- <input autocomplete="off" name="user[terms]" type="hidden" value="0">
1414
+ <input name="user[terms]" type="hidden" value="0">
1359
1415
  <input class="form-check-input" id="user_terms" name="user[terms]" type="checkbox" value="1">
1360
1416
  <label class="form-check-label" for="user_terms">Terms</label>
1361
1417
  </div>
@@ -1364,14 +1420,14 @@ This generates:
1364
1420
  </form>
1365
1421
  ```
1366
1422
 
1367
- 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.
1368
1424
 
1369
1425
  ### Floating Labels
1370
1426
 
1371
1427
  The `floating` option can be used to enable Bootstrap 5's floating labels. This option is supported on text fields
1372
1428
  and dropdowns. Here's an example:
1373
1429
 
1374
- ![Example 44](demo/doc/screenshots/bootstrap/readme/44_example.png "Example 44")
1430
+ ![Example 46](demo/doc/screenshots/bootstrap/readme/46_example.png "Example 46")
1375
1431
  ```erb
1376
1432
  <%= bootstrap_form_for(@user) do |f| %>
1377
1433
  <%= f.email_field :email, floating: true %>
@@ -1419,7 +1475,7 @@ Rails normally wraps fields with validation errors in a `div.field_with_errors`,
1419
1475
  By default, fields that have validation errors will be outlined in red and the
1420
1476
  error will be displayed below the field. Here's an example:
1421
1477
 
1422
- ![Example 45](demo/doc/screenshots/bootstrap/readme/45_example.png "Example 45")
1478
+ ![Example 47](demo/doc/screenshots/bootstrap/readme/47_example.png "Example 47")
1423
1479
  ```erb
1424
1480
  <%= bootstrap_form_for(@user_with_error) do |f| %>
1425
1481
  <%= f.email_field :email %>
@@ -1437,38 +1493,38 @@ Generated HTML:
1437
1493
  <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1438
1494
  <div class="mb-3">
1439
1495
  <label class="form-label required" for="user_email">Email</label>
1440
- <input class="form-control is-invalid" id="user_email" name="user[email]" required="required" type="email" value="steve.example.com">
1441
- <div class="invalid-feedback">is invalid</div>
1496
+ <input aria-describedby="user_email_feedback" class="form-control is-invalid" id="user_email" name="user[email]" required="required" type="email" value="steve.example.com">
1497
+ <div class="invalid-feedback" id="user_email_feedback">is invalid</div>
1442
1498
  </div>
1443
- <div class="mb-3">
1444
- <label class="form-label" for="user_misc">Misc</label>
1499
+ <div aria-labelledby="user_misc" class="mb-3" role="group">
1500
+ <div class="form-label" id="user_misc">Misc</div>
1445
1501
  <div class="form-check">
1446
- <input checked class="form-check-input is-invalid" id="user_misc_1" name="user[misc]" type="radio" value="1">
1502
+ <input aria-describedby="user_misc_feedback" checked class="form-check-input is-invalid" id="user_misc_1" name="user[misc]" type="radio" value="1">
1447
1503
  <label class="form-check-label" for="user_misc_1">Mind reading</label>
1448
1504
  </div>
1449
1505
  <div class="form-check">
1450
- <input class="form-check-input is-invalid" id="user_misc_2" name="user[misc]" type="radio" value="2">
1506
+ <input aria-describedby="user_misc_feedback" class="form-check-input is-invalid" id="user_misc_2" name="user[misc]" type="radio" value="2">
1451
1507
  <label class="form-check-label" for="user_misc_2">Farming</label>
1452
- <div class="invalid-feedback">is invalid</div>
1508
+ <div class="invalid-feedback" id="user_misc_feedback">is invalid</div>
1453
1509
  </div>
1454
1510
  </div>
1455
- <input autocomplete="off" id="user_preferences" name="user[preferences][]" type="hidden" value="">
1456
- <div class="mb-3">
1457
- <label class="form-label" for="user_preferences">Preferences</label>
1511
+ <input id="user_preferences" name="user[preferences][]" type="hidden" value="">
1512
+ <div aria-labelledby="user_preferences" class="mb-3" role="group">
1513
+ <div class="form-label" id="user_preferences">Preferences</div>
1458
1514
  <div class="form-check">
1459
- <input checked class="form-check-input is-invalid" id="user_preferences_1" name="user[preferences][]" type="checkbox" value="1">
1515
+ <input aria-describedby="user_preferences_feedback" checked class="form-check-input is-invalid" id="user_preferences_1" name="user[preferences][]" type="checkbox" value="1">
1460
1516
  <label class="form-check-label" for="user_preferences_1">Good</label>
1461
1517
  </div>
1462
1518
  <div class="form-check">
1463
- <input class="form-check-input is-invalid" id="user_preferences_2" name="user[preferences][]" type="checkbox" value="2">
1519
+ <input aria-describedby="user_preferences_feedback" class="form-check-input is-invalid" id="user_preferences_2" name="user[preferences][]" type="checkbox" value="2">
1464
1520
  <label class="form-check-label" for="user_preferences_2">Bad</label>
1465
- <div class="invalid-feedback">is invalid</div>
1521
+ <div class="invalid-feedback" id="user_preferences_feedback">is invalid</div>
1466
1522
  </div>
1467
1523
  </div>
1468
1524
  <div class="mb-3">
1469
1525
  <label class="form-label" for="user_address_attributes_street">Street</label>
1470
- <input class="form-control is-invalid" id="user_address_attributes_street" name="user[address_attributes][street]" type="text" value="Bar">
1471
- <div class="invalid-feedback">is invalid</div>
1526
+ <input aria-describedby="user_address_attributes_street_feedback" class="form-control is-invalid" id="user_address_attributes_street" name="user[address_attributes][street]" type="text" value="Bar">
1527
+ <div class="invalid-feedback" id="user_address_attributes_street_feedback">is invalid</div>
1472
1528
  </div>
1473
1529
  </form>
1474
1530
  ```
@@ -1486,7 +1542,7 @@ You can turn off inline errors for the entire form like this:
1486
1542
  You can also display validation errors in the field's label; just turn
1487
1543
  on the `:label_errors` option. Here's an example:
1488
1544
 
1489
- ![Example 46](demo/doc/screenshots/bootstrap/readme/46_example.png "Example 46")
1545
+ ![Example 48](demo/doc/screenshots/bootstrap/readme/48_example.png "Example 48")
1490
1546
  ```erb
1491
1547
  <%= bootstrap_form_for(@user_with_error, label_errors: true) do |f| %>
1492
1548
  <%= f.email_field :email %>
@@ -1498,8 +1554,8 @@ Generated HTML:
1498
1554
  ```html
1499
1555
  <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1500
1556
  <div class="mb-3">
1501
- <label class="form-label required text-danger" for="user_email">Email is invalid</label>
1502
- <input class="form-control is-invalid" id="user_email" name="user[email]" required="required" type="email" value="steve.example.com">
1557
+ <label class="form-label required text-danger" for="user_email" id="user_email_feedback">Email is invalid</label>
1558
+ <input aria-describedby="user_email_feedback" class="form-control is-invalid" id="user_email" name="user[email]" required="required" type="email" value="steve.example.com">
1503
1559
  </div>
1504
1560
  </form>
1505
1561
  ```
@@ -1519,7 +1575,7 @@ To display an error message with an error summary, you can use the
1519
1575
  `alert_message` helper. This won't output anything unless a model validation
1520
1576
  has failed.
1521
1577
 
1522
- ![Example 47](demo/doc/screenshots/bootstrap/readme/47_example.png "Example 47")
1578
+ ![Example 49](demo/doc/screenshots/bootstrap/readme/49_example.png "Example 49")
1523
1579
  ```erb
1524
1580
  <%= bootstrap_form_for @user_with_error do |f| %>
1525
1581
  <%= f.alert_message "Please fix the errors below." %>
@@ -1543,7 +1599,7 @@ Which outputs:
1543
1599
 
1544
1600
  You can turn off the error summary like this:
1545
1601
 
1546
- ![Example 48](demo/doc/screenshots/bootstrap/readme/48_example.png "Example 48")
1602
+ ![Example 50](demo/doc/screenshots/bootstrap/readme/50_example.png "Example 50")
1547
1603
  ```erb
1548
1604
  <%= bootstrap_form_for @user_with_error do |f| %>
1549
1605
  <%= f.alert_message "Please fix the errors below.", error_summary: false %>
@@ -1560,7 +1616,7 @@ This generates:
1560
1616
 
1561
1617
  To output a simple unordered list of errors, use the `error_summary` helper.
1562
1618
 
1563
- ![Example 49](demo/doc/screenshots/bootstrap/readme/49_example.png "Example 49")
1619
+ ![Example 51](demo/doc/screenshots/bootstrap/readme/51_example.png "Example 51")
1564
1620
  ```erb
1565
1621
  <%= bootstrap_form_for @user_with_error do |f| %>
1566
1622
  <%= f.error_summary %>
@@ -1583,9 +1639,10 @@ Which outputs:
1583
1639
 
1584
1640
  If you want to display a custom inline error for a specific attribute not represented by a form field, use the `errors_on` helper.
1585
1641
 
1586
- ![Example 50](demo/doc/screenshots/bootstrap/readme/50_example.png "Example 50")
1642
+ ![Example 52](demo/doc/screenshots/bootstrap/readme/52_example.png "Example 52")
1587
1643
  ```erb
1588
1644
  <%= bootstrap_form_for @user_with_error do |f| %>
1645
+ <input class="is-invalid" autocomplete="off" disabled type="hidden">
1589
1646
  <%= f.errors_on :email %>
1590
1647
  <% end %>
1591
1648
  ```
@@ -1594,15 +1651,19 @@ Which outputs:
1594
1651
 
1595
1652
  ```html
1596
1653
  <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1597
- <div class="invalid-feedback">Email is invalid</div>
1654
+ <input autocomplete="off" class="is-invalid" disabled type="hidden">
1655
+ <div class="invalid-feedback" id="user_email_feedback">Email is invalid</div>
1598
1656
  </form>
1599
1657
  ```
1600
1658
 
1659
+ Note that the `invalid-feedback` `div` is hidden unless there is a preceding element under the same parent that has class `is-invalid`. For the examples, we've artificially added a hidden input.
1660
+
1601
1661
  You can hide the attribute name like this:
1602
1662
 
1603
- ![Example 51](demo/doc/screenshots/bootstrap/readme/51_example.png "Example 51")
1663
+ ![Example 53](demo/doc/screenshots/bootstrap/readme/53_example.png "Example 53")
1604
1664
  ```erb
1605
1665
  <%= bootstrap_form_for @user_with_error do |f| %>
1666
+ <input class="is-invalid" autocomplete="off" disabled type="hidden">
1606
1667
  <%= f.errors_on :email, hide_attribute_name: true %>
1607
1668
  <% end %>
1608
1669
  ```
@@ -1611,15 +1672,17 @@ Which outputs:
1611
1672
 
1612
1673
  ```html
1613
1674
  <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1614
- <div class="invalid-feedback">is invalid</div>
1675
+ <input autocomplete="off" class="is-invalid" disabled type="hidden">
1676
+ <div class="invalid-feedback" id="user_email_feedback">is invalid</div>
1615
1677
  </form>
1616
1678
  ```
1617
1679
 
1618
1680
  You can also use a custom class for the wrapping div, like this:
1619
1681
 
1620
- ![Example 52](demo/doc/screenshots/bootstrap/readme/52_example.png "Example 52")
1682
+ ![Example 54](demo/doc/screenshots/bootstrap/readme/54_example.png "Example 54")
1621
1683
  ```erb
1622
1684
  <%= bootstrap_form_for @user_with_error do |f| %>
1685
+ <input class="is-invalid" autocomplete="off" disabled type="hidden">
1623
1686
  <%= f.errors_on :email, custom_class: 'custom-error' %>
1624
1687
  <% end %>
1625
1688
  ```
@@ -1628,10 +1691,13 @@ Which outputs:
1628
1691
 
1629
1692
  ```html
1630
1693
  <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1631
- <div class="custom-error">Email is invalid</div>
1694
+ <input autocomplete="off" class="is-invalid" disabled type="hidden">
1695
+ <div class="custom-error" id="user_email_feedback">Email is invalid</div>
1632
1696
  </form>
1633
1697
  ```
1634
1698
 
1699
+ Note that adding the custom class removes the default `invalid-feedback` class. If you still want the default `invalid-feedback` formatting, add it to your `custom_class`es.
1700
+
1635
1701
  ## Required Fields
1636
1702
 
1637
1703
  A label that is associated with a required field is automatically annotated with
@@ -1652,7 +1718,7 @@ ActiveModel::Validations::PresenceValidator.
1652
1718
 
1653
1719
  In cases where this behaviour is undesirable, use the `required` option to force the class to be present or absent:
1654
1720
 
1655
- ![Example 53](demo/doc/screenshots/bootstrap/readme/53_example.png "Example 53")
1721
+ ![Example 55](demo/doc/screenshots/bootstrap/readme/55_example.png "Example 55")
1656
1722
  ```erb
1657
1723
  <%= f.password_field :login, label: "New Username", required: true %>
1658
1724
  <%= f.password_field :password, label: "New Password", required: false %>
@@ -1675,7 +1741,7 @@ This generates:
1675
1741
 
1676
1742
  Adding a form control for a `belongs_to` field will automatically pick up the associated presence validator.
1677
1743
 
1678
- ![Example 54](demo/doc/screenshots/bootstrap/readme/54_example.png "Example 54")
1744
+ ![Example 56](demo/doc/screenshots/bootstrap/readme/56_example.png "Example 56")
1679
1745
  ```erb
1680
1746
  <%= bootstrap_form_for(@address, url: '/address') do |f| %>
1681
1747
  <%= f.collection_select :user_id, @users, :id, :email, include_blank: "Select a value" %>
@@ -1703,8 +1769,8 @@ Generated HTML:
1703
1769
  <input class="form-control" id="address_street" name="address[street]" type="text" value="Foo">
1704
1770
  </div>
1705
1771
  <div class="mb-3">
1706
- <label class="form-label" for="address_city">City</label>
1707
- <input class="form-control" id="address_city" name="address[city]" type="text">
1772
+ <label class="form-label required" for="address_city">City</label>
1773
+ <input class="form-control" id="address_city" name="address[city]" required="required" type="text">
1708
1774
  </div>
1709
1775
  <div class="mb-3">
1710
1776
  <label class="form-label" for="address_state">State</label>
@@ -1722,7 +1788,7 @@ Generated HTML:
1722
1788
 
1723
1789
  Fields can be disabled using the standard Rails form helper option.
1724
1790
 
1725
- ![Example 55](demo/doc/screenshots/bootstrap/readme/55_example.png "Example 55")
1791
+ ![Example 57](demo/doc/screenshots/bootstrap/readme/57_example.png "Example 57")
1726
1792
  ```erb
1727
1793
  <%= bootstrap_form_for @user do |f| %>
1728
1794
  <div class="row g-3">
@@ -1784,7 +1850,7 @@ Generated HTML:
1784
1850
  </div>
1785
1851
  <div class="col-auto">
1786
1852
  <div class="form-check mb-3">
1787
- <input autocomplete="off" disabled name="user[terms]" type="hidden" value="0">
1853
+ <input disabled name="user[terms]" type="hidden" value="0">
1788
1854
  <input class="form-check-input" disabled id="user_terms" name="user[terms]" type="checkbox" value="1">
1789
1855
  <label class="form-check-label" for="user_terms">Terms</label>
1790
1856
  </div>