bootstrap_form 5.0.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +31 -16
  3. data/.gitignore +15 -3
  4. data/.rubocop.yml +3 -1
  5. data/.yarnrc +5 -0
  6. data/CHANGELOG.md +53 -2
  7. data/CONTRIBUTING.md +110 -22
  8. data/Dangerfile +5 -5
  9. data/Dockerfile +6 -11
  10. data/Gemfile +5 -23
  11. data/README.md +805 -54
  12. data/RELEASING.md +16 -10
  13. data/Rakefile +7 -6
  14. data/bootstrap_form.gemspec +7 -10
  15. data/docker-compose.yml +9 -48
  16. data/gemfiles/6.0.gemfile +1 -1
  17. data/gemfiles/6.1.gemfile +1 -1
  18. data/gemfiles/7.0.gemfile +5 -0
  19. data/gemfiles/common.gemfile +28 -0
  20. data/gemfiles/edge.gemfile +3 -2
  21. data/lib/bootstrap_form/components/hints.rb +13 -4
  22. data/lib/bootstrap_form/components/labels.rb +4 -10
  23. data/lib/bootstrap_form/components/validation.rb +36 -19
  24. data/lib/bootstrap_form/form_builder.rb +9 -6
  25. data/lib/bootstrap_form/form_group.rb +15 -8
  26. data/lib/bootstrap_form/form_group_builder.rb +10 -7
  27. data/lib/bootstrap_form/helpers/bootstrap.rb +12 -9
  28. data/lib/bootstrap_form/helpers/field.rb +26 -0
  29. data/lib/bootstrap_form/helpers.rb +1 -0
  30. data/lib/bootstrap_form/inputs/check_box.rb +26 -8
  31. data/lib/bootstrap_form/inputs/collection_check_boxes.rb +5 -1
  32. data/lib/bootstrap_form/inputs/collection_select.rb +1 -1
  33. data/lib/bootstrap_form/inputs/grouped_collection_select.rb +1 -1
  34. data/lib/bootstrap_form/inputs/radio_button.rb +15 -10
  35. data/lib/bootstrap_form/version.rb +2 -1
  36. data/lib/bootstrap_form.rb +1 -1
  37. metadata +17 -88
  38. data/demo/.postcssrc.yml +0 -3
  39. data/demo/README.md +0 -17
  40. data/demo/Rakefile +0 -6
  41. data/demo/app/assets/config/manifest.js +0 -1
  42. data/demo/app/assets/stylesheets/actiontext.scss +0 -38
  43. data/demo/app/assets/stylesheets/application.scss +0 -1
  44. data/demo/app/controllers/application_controller.rb +0 -2
  45. data/demo/app/controllers/bootstrap_controller.rb +0 -14
  46. data/demo/app/helpers/bootstrap_helper.rb +0 -27
  47. data/demo/app/javascript/channels/consumer.js +0 -6
  48. data/demo/app/javascript/channels/index.js +0 -5
  49. data/demo/app/javascript/packs/application.js +0 -11
  50. data/demo/app/models/address.rb +0 -3
  51. data/demo/app/models/application_record.rb +0 -3
  52. data/demo/app/models/faux_user.rb +0 -9
  53. data/demo/app/models/super_user.rb +0 -2
  54. data/demo/app/models/user.rb +0 -11
  55. data/demo/app/views/active_storage/blobs/_blob.html.erb +0 -14
  56. data/demo/app/views/bootstrap/form.html.erb +0 -67
  57. data/demo/app/views/layouts/application.html.erb +0 -68
  58. data/demo/bin/bundle +0 -3
  59. data/demo/bin/rails +0 -4
  60. data/demo/bin/rake +0 -4
  61. data/demo/bin/setup +0 -36
  62. data/demo/bin/update +0 -31
  63. data/demo/bin/webpack +0 -15
  64. data/demo/bin/webpack-dev-server +0 -15
  65. data/demo/bin/yarn +0 -11
  66. data/demo/config/application.rb +0 -21
  67. data/demo/config/boot.rb +0 -5
  68. data/demo/config/database.yml +0 -21
  69. data/demo/config/environment.rb +0 -5
  70. data/demo/config/environments/development.rb +0 -60
  71. data/demo/config/environments/production.rb +0 -48
  72. data/demo/config/environments/test.rb +0 -46
  73. data/demo/config/initializers/application_controller_renderer.rb +0 -8
  74. data/demo/config/initializers/assets.rb +0 -14
  75. data/demo/config/initializers/backtrace_silencers.rb +0 -7
  76. data/demo/config/initializers/cookies_serializer.rb +0 -5
  77. data/demo/config/initializers/filter_parameter_logging.rb +0 -4
  78. data/demo/config/initializers/inflections.rb +0 -16
  79. data/demo/config/initializers/mime_types.rb +0 -4
  80. data/demo/config/initializers/wrap_parameters.rb +0 -14
  81. data/demo/config/locales/en.yml +0 -33
  82. data/demo/config/puma.rb +0 -56
  83. data/demo/config/routes.rb +0 -5
  84. data/demo/config/spring.rb +0 -6
  85. data/demo/config/storage.yml +0 -35
  86. data/demo/config/webpack/development.js +0 -5
  87. data/demo/config/webpack/environment.js +0 -3
  88. data/demo/config/webpack/production.js +0 -5
  89. data/demo/config/webpack/test.js +0 -5
  90. data/demo/config/webpacker.yml +0 -92
  91. data/demo/config.ru +0 -5
  92. data/demo/db/schema.rb +0 -69
  93. data/demo/log/.keep +0 -0
  94. data/demo/package.json +0 -17
  95. data/demo/public/favicon.ico +0 -0
  96. data/demo/test/fixtures/action_text/rich_texts.yml +0 -4
  97. data/demo/yarn.lock +0 -6257
  98. data/gemfiles/5.2.gemfile +0 -4
data/README.md CHANGED
@@ -25,16 +25,24 @@ 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 2.5+
29
- * Rails 5.2+
28
+ * Ruby 3.0+ (https://www.ruby-lang.org/en/downloads/branches/)
29
+ * Rails 6.0+ (https://guides.rubyonrails.org/maintenance_policy.html)
30
30
  * Bootstrap 5.0+
31
31
 
32
32
  ## Installation
33
33
 
34
- Add it to your Gemfile:
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`:
35
35
 
36
36
  ```ruby
37
- gem "bootstrap_form", "~> 5.0"
37
+ gem "bootstrap", "~> 5.0"
38
+ ```
39
+
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`.
41
+
42
+ Add the `bootstrap_form` gem to your `Gemfile`:
43
+
44
+ ```ruby
45
+ gem "bootstrap_form", "~> 5.2"
38
46
  ```
39
47
 
40
48
  Then:
@@ -60,6 +68,7 @@ If you followed the [official bootstrap installation guide](https://github.com/t
60
68
 
61
69
  To get started, use the `bootstrap_form_for` helper in place of the Rails `form_for` helper. Here's an example:
62
70
 
71
+ ![Example 0](demo/doc/screenshots/bootstrap/readme/00_example.png "Example 0")
63
72
  ```erb
64
73
  <%= bootstrap_form_for(@user) do |f| %>
65
74
  <%= f.email_field :email %>
@@ -74,19 +83,19 @@ This generates the following HTML:
74
83
  ```html
75
84
  <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
76
85
  <div class="mb-3">
77
- <label class="form-label" for="user_email">Email</label>
78
- <input class="form-control" id="user_email" name="user[email]" type="email">
86
+ <label class="form-label required" for="user_email">Email</label>
87
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
79
88
  </div>
80
89
  <div class="mb-3">
81
90
  <label class="form-label" for="user_password">Password</label>
82
91
  <input class="form-control" id="user_password" name="user[password]" type="password">
83
92
  </div>
84
- <div class="form-check">
85
- <input name="user[remember_me]" type="hidden" value="0">
93
+ <div class="form-check mb-3">
94
+ <input autocomplete="off" name="user[remember_me]" type="hidden" value="0">
86
95
  <input class="form-check-input" id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
87
96
  <label class="form-check-label" for="user_remember_me">Remember me</label>
88
97
  </div>
89
- <input class="btn btn-secondary" name="commit" type="submit" value="Log In">
98
+ <input class="btn btn-secondary" data-disable-with="Log In" name="commit" type="submit" value="Log In">
90
99
  </form>
91
100
  ```
92
101
 
@@ -94,6 +103,7 @@ This generates the following HTML:
94
103
 
95
104
  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:
96
105
 
106
+ ![Example 1](demo/doc/screenshots/bootstrap/readme/01_example.png "Example 1")
97
107
  ```erb
98
108
  <%= bootstrap_form_tag url: '/subscribe' do |f| %>
99
109
  <%= f.email_field :email, value: 'name@example.com' %>
@@ -101,16 +111,29 @@ If your form is not backed by a model, use the `bootstrap_form_tag`. Usage of th
101
111
  <% end %>
102
112
  ```
103
113
 
114
+ This generates:
115
+
116
+ ```html
117
+ <form accept-charset="UTF-8" action="/subscribe" method="post">
118
+ <div class="mb-3">
119
+ <label class="form-label" for="email">Email</label>
120
+ <input class="form-control" id="email" name="email" type="email" value="name@example.com">
121
+ </div>
122
+ <input class="btn btn-secondary" data-disable-with="Save " name="commit" type="submit" value="Save ">
123
+ </form>
124
+ ```
125
+
104
126
  ### bootstrap_form_with
105
127
 
106
128
  Note that `form_with` in Rails 5.1 does not add IDs to form elements and labels by default, which are both important to Bootstrap markup. This behaviour is corrected in Rails 5.2.
107
129
 
108
130
  To get started, just use the `bootstrap_form_with` helper in place of `form_with`. Here's an example:
109
131
 
132
+ ![Example 2](demo/doc/screenshots/bootstrap/readme/02_example.png "Example 2")
110
133
  ```erb
111
134
  <%= bootstrap_form_with(model: @user, local: true) do |f| %>
112
135
  <%= f.email_field :email %>
113
- <%= f.password_field :password %>
136
+ <%= f.password_field :password, help: 'A good password should be at least six characters long' %>
114
137
  <%= f.check_box :remember_me %>
115
138
  <%= f.submit "Log In" %>
116
139
  <% end %>
@@ -119,23 +142,22 @@ To get started, just use the `bootstrap_form_with` helper in place of `form_with
119
142
  This generates:
120
143
 
121
144
  ```html
122
- <form action="/users" accept-charset="UTF-8" method="post">
123
- <input name="utf8" type="hidden" value="&#x2713;" />
145
+ <form accept-charset="UTF-8" action="/users" method="post">
124
146
  <div class="mb-3">
125
147
  <label class="form-label required" for="user_email">Email</label>
126
- <input class="form-control" type="email" value="steve@example.com" name="user[email]" />
148
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
127
149
  </div>
128
150
  <div class="mb-3">
129
151
  <label class="form-label" for="user_password">Password</label>
130
- <input class="form-control" type="password" name="user[password]" />
152
+ <input class="form-control" id="user_password" name="user[password]" type="password">
131
153
  <small class="form-text text-muted">A good password should be at least six characters long</small>
132
154
  </div>
133
- <div class="form-check">
134
- <input name="user[remember_me]" type="hidden" value="0">
155
+ <div class="form-check mb-3">
156
+ <input autocomplete="off" name="user[remember_me]" type="hidden" value="0">
135
157
  <input class="form-check-input" id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
136
158
  <label class="form-check-label" for="user_remember_me">Remember me</label>
137
159
  </div>
138
- <input type="submit" name="commit" value="Log In" class="btn btn-secondary" data-disable-with="Log In" />
160
+ <input class="btn btn-secondary" data-disable-with="Log In" name="commit" type="submit" value="Log In">
139
161
  </form>
140
162
  ```
141
163
 
@@ -212,41 +234,93 @@ The options for the form helpers that aren't in the exceptions list are describe
212
234
 
213
235
  Use the `label` option if you want to specify the field's label text:
214
236
 
237
+ ![Example 3](demo/doc/screenshots/bootstrap/readme/03_example.png "Example 3")
215
238
  ```erb
216
239
  <%= f.password_field :password_confirmation, label: "Confirm Password" %>
217
240
  ```
218
241
 
219
- To hide a label, use the `hide_label: true` option. This adds the `sr-only`
242
+ This generates:
243
+
244
+ ```html
245
+ <div class="mb-3">
246
+ <label class="form-label" for="user_password_confirmation">Confirm Password</label>
247
+ <input class="form-control" id="user_password_confirmation" name="user[password_confirmation]" type="password">
248
+ </div>
249
+ ```
250
+
251
+ To hide a label, use the `hide_label: true` option. This adds the `visually-hidden`
220
252
  class, which keeps your labels accessible to those using screen readers.
221
253
 
254
+ ![Example 4](demo/doc/screenshots/bootstrap/readme/04_example.png "Example 4")
222
255
  ```erb
223
256
  <%= f.text_area :comment, hide_label: true, placeholder: "Leave a comment..." %>
224
257
  ```
225
258
 
259
+ This generates:
260
+
261
+ ```html
262
+ <div class="mb-3">
263
+ <label class="form-label visually-hidden" for="user_comment">Comment</label>
264
+ <textarea class="form-control" id="user_comment" name="user[comment]" placeholder="Leave a comment...">
265
+ </textarea>
266
+ </div>
267
+ ```
268
+
226
269
  To add custom classes to the field's label:
227
270
 
271
+ ![Example 5](demo/doc/screenshots/bootstrap/readme/05_example.png "Example 5")
228
272
  ```erb
229
273
  <%= f.text_field :email, label_class: "custom-class" %>
230
274
  ```
231
275
 
276
+ This generates:
277
+
278
+ ```html
279
+ <div class="mb-3">
280
+ <label class="form-label custom-class required" for="user_email">Email</label>
281
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="text" value="steve@example.com">
282
+ </div>
283
+ ```
284
+
232
285
  Or you can add the label as input placeholder instead (this automatically hides the label):
233
286
 
287
+ ![Example 6](demo/doc/screenshots/bootstrap/readme/06_example.png "Example 6")
234
288
  ```erb
235
289
  <%= f.text_field :email, label_as_placeholder: true %>
236
290
  ```
237
291
 
292
+ This generates:
293
+
294
+ ```html
295
+ <div class="mb-3">
296
+ <label class="form-label visually-hidden required" for="user_email">Email</label>
297
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" placeholder="Email" required="required" type="text" value="steve@example.com">
298
+ </div>
299
+ ```
300
+
238
301
  ### Input Elements / Controls
239
302
 
240
303
  To specify the class of the generated input tag, use the `control_class` option:
241
304
 
305
+ ![Example 7](demo/doc/screenshots/bootstrap/readme/07_example.png "Example 7")
242
306
  ```erb
243
307
  <%= f.text_field :email, control_class: "custom-class" %>
244
308
  ```
245
309
 
310
+ This generates:
311
+
312
+ ```html
313
+ <div class="mb-3">
314
+ <label class="form-label required" for="user_email">Email</label>
315
+ <input aria-required="true" class="custom-class" id="user_email" name="user[email]" required="required" type="text" value="steve@example.com">
316
+ </div>
317
+ ```
318
+
246
319
  ### Help Text
247
320
 
248
321
  To add help text, use the `help` option:
249
322
 
323
+ ![Example 8](demo/doc/screenshots/bootstrap/readme/08_example.png "Example 8")
250
324
  ```erb
251
325
  <%= f.password_field :password, help: "Must be at least 6 characters long" %>
252
326
  ```
@@ -254,7 +328,11 @@ To add help text, use the `help` option:
254
328
  This generates:
255
329
 
256
330
  ```html
257
- <small class="form-text text-muted">Must be at least 6 characters long</small>
331
+ <div class="mb-3">
332
+ <label class="form-label" for="user_password">Password</label>
333
+ <input class="form-control" id="user_password" name="user[password]" type="password">
334
+ <small class="form-text text-muted">Must be at least 6 characters long</small>
335
+ </div>
258
336
  ```
259
337
 
260
338
  This gem is also aware of help messages in locale translation files (i18n):
@@ -287,41 +365,108 @@ option or turn them off completely by passing `help: false`.
287
365
 
288
366
  You can pass `prepend` and/or `append` options to input fields:
289
367
 
368
+ ![Example 9](demo/doc/screenshots/bootstrap/readme/09_example.png "Example 9")
290
369
  ```erb
291
370
  <%= f.text_field :price, prepend: "$", append: ".00" %>
292
371
  ```
293
372
 
373
+ This generates:
374
+
375
+ ```html
376
+ <div class="mb-3">
377
+ <label class="form-label" for="user_price">Price</label>
378
+ <div class="input-group">
379
+ <span class="input-group-text">$</span>
380
+ <input class="form-control" id="user_price" name="user[price]" type="text">
381
+ <span class="input-group-text">.00</span>
382
+ </div>
383
+ </div>
384
+ ```
385
+
294
386
  If you want to attach multiple items to the input, pass them as an array:
295
387
 
388
+ ![Example 10](demo/doc/screenshots/bootstrap/readme/10_example.png "Example 10")
296
389
  ```erb
297
390
  <%= f.text_field :price, prepend: ['Net', '$'], append: ['.00', 'per day'] %>
298
391
  ```
299
392
 
393
+ This generates:
394
+
395
+ ```html
396
+ <div class="mb-3">
397
+ <label class="form-label" for="user_price">Price</label>
398
+ <div class="input-group">
399
+ <span class="input-group-text">Net</span>
400
+ <span class="input-group-text">$</span>
401
+ <input class="form-control" id="user_price" name="user[price]" type="text">
402
+ <span class="input-group-text">.00</span>
403
+ <span class="input-group-text">per day</span>
404
+ </div>
405
+ </div>
406
+ ```
407
+
300
408
  You can also prepend and append buttons. Note: The buttons must contain the
301
409
  `btn` class to generate the correct markup.
302
410
 
411
+ ![Example 11](demo/doc/screenshots/bootstrap/readme/11_example.png "Example 11")
303
412
  ```erb
304
413
  <%= f.text_field :search, append: link_to("Go", "#", class: "btn btn-secondary") %>
305
414
  ```
306
415
 
416
+ This generates:
417
+
418
+ ```html
419
+ <div class="mb-3">
420
+ <label class="form-label" for="user_search">Search</label>
421
+ <div class="input-group">
422
+ <input class="form-control" id="user_search" name="user[search]" type="text">
423
+ <a class="btn btn-secondary" href="#">Go</a>
424
+ </div>
425
+ </div>
426
+ ```
427
+
307
428
  To add a class to the input group wrapper, use the `:input_group_class` option.
308
429
 
430
+ ![Example 12](demo/doc/screenshots/bootstrap/readme/12_example.png "Example 12")
309
431
  ```erb
310
432
  <%= f.email_field :email, append: f.primary('Subscribe'), input_group_class: 'input-group-lg' %>
311
433
  ```
312
434
 
435
+ This generates:
436
+
437
+ ```html
438
+ <div class="mb-3">
439
+ <label class="form-label required" for="user_email">Email</label>
440
+ <div class="input-group input-group-lg">
441
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
442
+ <input class="btn btn-primary" data-disable-with="Subscribe" name="commit" type="submit" value="Subscribe">
443
+ </div>
444
+ </div>
445
+ ```
446
+
313
447
  ### Additional Form Group Attributes
314
448
 
315
449
  Bootstrap mark-up dictates that most input field types have the label and input wrapped in a `div.mb-3`.
316
450
 
317
- If you want to add an additional CSS class or any other attribute to the form group div, you can use the `wrapper: { class: 'additional-class', data: { foo: 'bar' } }` option.
451
+ If you want to change the CSS class or any other attribute to the form group div, you can use the `wrapper: { class: 'mb-3 additional-class', data: { foo: 'bar' } }` option.
318
452
 
453
+ ![Example 13](demo/doc/screenshots/bootstrap/readme/13_example.png "Example 13")
319
454
  ```erb
320
- <%= f.text_field :name, wrapper: { class: 'has-warning', data: { foo: 'bar' } } %>
455
+ <%= f.text_field :name, wrapper: { class: 'mb-3 has-warning', data: { foo: 'bar' } } %>
456
+ ```
457
+
458
+ This generates:
459
+
460
+ ```html
461
+ <div class="mb-3 has-warning" data-foo="bar">
462
+ <label class="form-label" for="user_name">Name</label>
463
+ <input class="form-control" id="user_name" name="user[name]" type="text">
464
+ </div>
321
465
  ```
322
466
 
323
467
  Which produces the following output:
324
468
 
469
+ ![Example 14](demo/doc/screenshots/bootstrap/readme/14_example.png "Example 14")
325
470
  ```erb
326
471
  <div class="mb-3 has-warning" data-foo="bar">
327
472
  <label class="form-label form-control-label" for="user_name">Id</label>
@@ -329,16 +474,37 @@ Which produces the following output:
329
474
  </div>
330
475
  ```
331
476
 
332
- If you only want to set the class on the form group div, you can use the `wrapper_class` option. It's just a short form of `wrapper: { class: 'additional-class' }`.
477
+ This generates:
478
+
479
+ ```html
480
+ <div class="mb-3 has-warning" data-foo="bar">
481
+ <label class="form-label form-control-label" for="user_name">Id</label>
482
+ <input class="form-control" id="user_name" name="user[name]" type="text">
483
+ </div>
484
+ ```
485
+
486
+ If you only want to set the class on the form group div, you can use the `wrapper_class` option: `wrapper_class: 'mb-3 additional-class'`.
487
+ It's just a short form of `wrapper: { class: 'mb-3 additional-class' }`.
488
+
489
+ If you don't want any class on the form group div, you can set it to `false`: `wrapper_class: false`.
333
490
 
334
491
  ### Suppressing the Form Group Altogether
335
492
 
336
493
  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:
337
494
 
338
- ```ruby
339
- f.form_group :user do
340
- f.email_field :email, wrapper: false
341
- end
495
+ ![Example 15](demo/doc/screenshots/bootstrap/readme/15_example.png "Example 15")
496
+ ```erb
497
+ <%= f.form_group :user do %>
498
+ <%= f.email_field :email, wrapper: false %>
499
+ <% end %>
500
+ ```
501
+
502
+ Generated HTML:
503
+
504
+ ```html
505
+ <div class="mb-3">
506
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
507
+ </div>
342
508
  ```
343
509
 
344
510
  Note that Bootstrap relies on the form group div to correctly format most fields, so if you use the `wrapper: false` option, you should provide your own form group div around the input field. You can write your own HTML, or use the `form_group` helper.
@@ -347,16 +513,30 @@ Note that Bootstrap relies on the form group div to correctly format most fields
347
513
 
348
514
  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:
349
515
 
516
+ ![Example 16](demo/doc/screenshots/bootstrap/readme/16_example.png "Example 16")
350
517
  ```erb
351
518
  <%= f.select :product, [["Apple", 1], ["Grape", 2]], { label: "Choose your favorite fruit:", wrapper: { class: 'has-warning', data: { foo: 'bar' } } }, { class: "selectpicker" } %>
352
519
  ```
353
520
 
521
+ This generates:
522
+
523
+ ```html
524
+ <div class="has-warning" data-foo="bar">
525
+ <label class="form-label" for="user_product">Choose your favorite fruit:</label>
526
+ <select class="form-select selectpicker" id="user_product" name="user[product]">
527
+ <option value="1">Apple</option>
528
+ <option value="2">Grape</option>
529
+ </select>
530
+ </div>
531
+ ```
532
+
354
533
  ## Checkboxes and Radios
355
534
 
356
535
  Checkboxes and radios should be placed inside of a `form_group` to render
357
536
  properly. The following example ensures that the entire form group will display
358
537
  an error if an associated validations fails:
359
538
 
539
+ ![Example 17](demo/doc/screenshots/bootstrap/readme/17_example.png "Example 17")
360
540
  ```erb
361
541
  <%= f.form_group :skill_level, label: { text: "Skill" }, help: "Optional Help Text" do %>
362
542
  <%= f.radio_button :skill_level, 0, label: "Novice", checked: true %>
@@ -369,8 +549,37 @@ an error if an associated validations fails:
369
549
  <% end %>
370
550
  ```
371
551
 
552
+ This generates:
553
+
554
+ ```html
555
+ <div class="mb-3">
556
+ <label class="form-label" for="user_skill_level">Skill</label>
557
+ <div class="form-check">
558
+ <input checked class="form-check-input" id="user_skill_level_0" name="user[skill_level]" type="radio" value="0">
559
+ <label class="form-check-label" for="user_skill_level_0">Novice</label>
560
+ </div>
561
+ <div class="form-check">
562
+ <input class="form-check-input" id="user_skill_level_1" name="user[skill_level]" type="radio" value="1">
563
+ <label class="form-check-label" for="user_skill_level_1">Intermediate</label>
564
+ </div>
565
+ <div class="form-check">
566
+ <input class="form-check-input" id="user_skill_level_2" name="user[skill_level]" type="radio" value="2">
567
+ <label class="form-check-label" for="user_skill_level_2">Advanced</label>
568
+ </div>
569
+ <small class="form-text text-muted">Optional Help Text</small>
570
+ </div>
571
+ <div class="mb-3">
572
+ <div class="form-check mb-3">
573
+ <input autocomplete="off" name="user[terms]" type="hidden" value="0">
574
+ <input class="form-check-input" id="user_terms" name="user[terms]" type="checkbox" value="1">
575
+ <label class="form-check-label" for="user_terms">I agree to the Terms of Service</label>
576
+ </div>
577
+ </div>
578
+ ```
579
+
372
580
  You can also create a checkbox using a block:
373
581
 
582
+ ![Example 18](demo/doc/screenshots/bootstrap/readme/18_example.png "Example 18")
374
583
  ```erb
375
584
  <%= f.form_group :terms, label: { text: "Optional Label" } do %>
376
585
  <%= f.check_box :terms do %>
@@ -379,8 +588,24 @@ You can also create a checkbox using a block:
379
588
  <% end %>
380
589
  ```
381
590
 
591
+ This generates:
592
+
593
+ ```html
594
+ <div class="mb-3">
595
+ <label class="form-label" for="user_terms">Optional Label</label>
596
+ <div class="form-check mb-3">
597
+ <input autocomplete="off" name="user[terms]" type="hidden" value="0">
598
+ <input class="form-check-input" id="user_terms" name="user[terms]" type="checkbox" value="1">
599
+ <label class="form-check-label" for="user_terms">
600
+ You need to check this box to accept our terms of service and privacy policy
601
+ </label>
602
+ </div>
603
+ </div>
604
+ ```
605
+
382
606
  To display checkboxes and radios inline, pass the `inline: true` option:
383
607
 
608
+ ![Example 19](demo/doc/screenshots/bootstrap/readme/19_example.png "Example 19")
384
609
  ```erb
385
610
  <%= f.form_group :skill_level, label: { text: "Skill" } do %>
386
611
  <%= f.radio_button :skill_level, 0, label: "Novice", inline: true %>
@@ -389,30 +614,122 @@ To display checkboxes and radios inline, pass the `inline: true` option:
389
614
  <% end %>
390
615
  ```
391
616
 
617
+ This generates:
618
+
619
+ ```html
620
+ <div class="mb-3">
621
+ <label class="form-label" for="user_skill_level">Skill</label>
622
+ <div class="form-check form-check-inline">
623
+ <input class="form-check-input" id="user_skill_level_0" name="user[skill_level]" type="radio" value="0">
624
+ <label class="form-check-label" for="user_skill_level_0">Novice</label>
625
+ </div>
626
+ <div class="form-check form-check-inline">
627
+ <input class="form-check-input" id="user_skill_level_1" name="user[skill_level]" type="radio" value="1">
628
+ <label class="form-check-label" for="user_skill_level_1">Intermediate</label>
629
+ </div>
630
+ <div class="form-check form-check-inline">
631
+ <input class="form-check-input" id="user_skill_level_2" name="user[skill_level]" type="radio" value="2">
632
+ <label class="form-check-label" for="user_skill_level_2">Advanced</label>
633
+ </div>
634
+ </div>
635
+ ```
636
+
392
637
  Check boxes and radio buttons are wrapped in a `div.form-check`. You can add classes to this `div` with the `:wrapper_class` option:
393
638
 
639
+ ![Example 20](demo/doc/screenshots/bootstrap/readme/20_example.png "Example 20")
394
640
  ```erb
395
641
  <%= f.radio_button :skill_level, 0, label: "Novice", inline: true, wrapper_class: "w-auto" %>
396
642
  ```
397
643
 
644
+ This generates:
645
+
646
+ ```html
647
+ <div class="form-check form-check-inline w-auto">
648
+ <input class="form-check-input" id="user_skill_level_0" name="user[skill_level]" type="radio" value="0">
649
+ <label class="form-check-label" for="user_skill_level_0">Novice</label>
650
+ </div>
651
+ ```
652
+
653
+ You can also add a style to the tag using the `wrapper` option:
654
+
655
+ ![Example 21](demo/doc/screenshots/bootstrap/readme/21_example.png "Example 21")
656
+ ```erb
657
+ <%= f.check_box :skilled, inline: true, wrapper: {style: "color: green"} %>
658
+ <%= f.radio_button :skill_level, 0, label: "Novice", inline: true, wrapper: {class: 'w-auto', style: "color: red"} %>
659
+ ```
660
+
661
+ This generates:
662
+
663
+ ```html
664
+ <div class="form-check form-check-inline mb-3" style="color: green">
665
+ <input autocomplete="off" name="user[skilled]" type="hidden" value="0">
666
+ <input class="form-check-input" id="user_skilled" name="user[skilled]" type="checkbox" value="1">
667
+ <label class="form-check-label" for="user_skilled">Skilled</label>
668
+ </div>
669
+ <div class="form-check form-check-inline w-auto" style="color: red">
670
+ <input class="form-check-input" id="user_skill_level_0" name="user[skill_level]" type="radio" value="0">
671
+ <label class="form-check-label" for="user_skill_level_0">Novice</label>
672
+ </div>
673
+ ```
674
+
398
675
  ### Switches
399
676
 
400
677
  To render checkboxes as switches with Bootstrap 4.2+, use `switch: true`:
401
678
 
679
+ ![Example 22](demo/doc/screenshots/bootstrap/readme/22_example.png "Example 22")
402
680
  ```erb
403
681
  <%= f.check_box :remember_me, switch: true %>
404
682
  ```
405
683
 
684
+ This generates:
685
+
686
+ ```html
687
+ <div class="form-check mb-3 form-switch">
688
+ <input autocomplete="off" name="user[remember_me]" type="hidden" value="0">
689
+ <input class="form-check-input" id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
690
+ <label class="form-check-label" for="user_remember_me">Remember me</label>
691
+ </div>
692
+ ```
693
+
406
694
  ### Collections
407
695
 
408
696
  `bootstrap_form` also provides helpers that automatically create the
409
697
  `form_group` and the `radio_button`s or `check_box`es for you:
410
698
 
699
+ ![Example 23](demo/doc/screenshots/bootstrap/readme/23_example.png "Example 23")
411
700
  ```erb
412
701
  <%= f.collection_radio_buttons :skill_level, Skill.all, :id, :name %>
413
702
  <%= f.collection_check_boxes :skills, Skill.all, :id, :name %>
414
703
  ```
415
704
 
705
+ This generates:
706
+
707
+ ```html
708
+ <div class="mb-3">
709
+ <label class="form-label" for="user_skill_level">Skill level</label>
710
+ <div class="form-check">
711
+ <input class="form-check-input" id="user_skill_level_1" name="user[skill_level]" type="radio" value="1">
712
+ <label class="form-check-label" for="user_skill_level_1">Mind reading</label>
713
+ </div>
714
+ <div class="form-check">
715
+ <input class="form-check-input" id="user_skill_level_2" name="user[skill_level]" type="radio" value="2">
716
+ <label class="form-check-label" for="user_skill_level_2">Farming</label>
717
+ </div>
718
+ </div>
719
+ <input autocomplete="off" id="user_skills" multiple name="user[skills][]" type="hidden" value="">
720
+ <div class="mb-3">
721
+ <label class="form-label" for="user_skills">Skills</label>
722
+ <div class="form-check">
723
+ <input class="form-check-input" id="user_skills_1" name="user[skills][]" type="checkbox" value="1">
724
+ <label class="form-check-label" for="user_skills_1">Mind reading</label>
725
+ </div>
726
+ <div class="form-check">
727
+ <input class="form-check-input" id="user_skills_2" name="user[skills][]" type="checkbox" value="2">
728
+ <label class="form-check-label" for="user_skills_2">Farming</label>
729
+ </div>
730
+ </div>
731
+ ```
732
+
416
733
  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.
417
734
 
418
735
  Collection methods accept these options:
@@ -422,39 +739,98 @@ Collection methods accept these options:
422
739
  * `:help`: Add a help span to the `form_group`
423
740
  * Other options will be forwarded to the `radio_button`/`check_box` method
424
741
 
742
+ ## Range Controls
743
+
744
+ You can create a range control like this:
745
+
746
+ ![Example 24](demo/doc/screenshots/bootstrap/readme/24_example.png "Example 24")
747
+ ```erb
748
+ <%= f.range_field :excellence %>
749
+ ```
750
+
751
+ This generates:
752
+
753
+ ```html
754
+ <div class="mb-3">
755
+ <label class="form-label" for="user_excellence">Excellence</label>
756
+ <input class="form-control" id="user_excellence" name="user[excellence]" type="range">
757
+ </div>
758
+ ```
759
+
425
760
  ## Static Controls
426
761
 
427
762
  You can create a static control like this:
428
763
 
764
+ ![Example 25](demo/doc/screenshots/bootstrap/readme/25_example.png "Example 25")
429
765
  ```erb
430
766
  <%= f.static_control :email %>
431
767
  ```
432
768
 
433
- Here's the output for a horizontal layout:
769
+ This generates:
434
770
 
435
771
  ```html
436
772
  <div class="mb-3">
437
- <label class="form-label col-sm-2 form-control-label" for="user_email">Email</label>
438
- <div class="col-sm-10">
439
- <input class="form-control-plaintext" id="user_email" name="user[email]" readonly="readonly" type="text" value="test@email.com"/>
440
- </div>
773
+ <label class="form-label required" for="user_email">Email</label>
774
+ <input aria-required="true" class="form-control-plaintext" id="user_email" name="user[email]" readonly required="required" type="text" value="steve@example.com">
441
775
  </div>
442
776
  ```
443
777
 
778
+ Here's the output for a horizontal layout:
779
+
780
+ ![Example 26](demo/doc/screenshots/bootstrap/readme/26_example.png "Example 26")
781
+ ```erb
782
+ <%= bootstrap_form_for(@user, layout: :horizontal) do |f| %>
783
+ <%= f.static_control :email %>
784
+ <% end %>
785
+ ```
786
+
787
+ This generates:
788
+
789
+ ```html
790
+ <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
791
+ <div class="mb-3 row">
792
+ <label class="form-label col-form-label col-sm-2 required" for="user_email">Email</label>
793
+ <div class="col-sm-10">
794
+ <input aria-required="true" class="form-control-plaintext" id="user_email" name="user[email]" readonly required="required" type="text" value="steve@example.com">
795
+ </div>
796
+ </div>
797
+ </form>
798
+ ```
799
+
444
800
  You can also create a static control that isn't based on a model attribute:
445
801
 
802
+ ![Example 27](demo/doc/screenshots/bootstrap/readme/27_example.png "Example 27")
446
803
  ```erb
447
804
  <%= f.static_control :field_name, label: "Custom Static Control", value: "Content Here" %>
448
805
  ```
449
806
 
807
+ This generates:
808
+
809
+ ```html
810
+ <div class="mb-3">
811
+ <label class="form-label" for="user_field_name">Custom Static Control</label>
812
+ <input class="form-control-plaintext" id="user_field_name" name="user[field_name]" readonly type="text" value="Content Here">
813
+ </div>
814
+ ```
815
+
450
816
  `field_name` may be any name that isn't already used in the form. Note that you may get "unpermitted parameter" messages in your log file with this approach.
451
817
 
452
818
  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:
453
819
 
820
+ ![Example 28](demo/doc/screenshots/bootstrap/readme/28_example.png "Example 28")
454
821
  ```erb
455
822
  <%= f.static_control label: "Custom Static Control", value: "Content Here", name: nil %>
456
823
  ```
457
824
 
825
+ This generates:
826
+
827
+ ```html
828
+ <div class="mb-3">
829
+ <label class="form-label" for="user_">Custom Static Control</label>
830
+ <input class="form-control-plaintext" id="user_" readonly type="text" value="Content Here">
831
+ </div>
832
+ ```
833
+
458
834
  (If you neither provide a field name nor `name: nil`, the Rails code that submits the form will give a JavaScript error.)
459
835
 
460
836
  Prior to version 4 of `bootstrap_form`, you could pass a block to the `static_control` method.
@@ -475,28 +851,50 @@ this defining these selects as `inline-block` and a width of `auto`.
475
851
  The `btn btn-secondary` CSS classes are automatically added to your submit
476
852
  buttons.
477
853
 
854
+ ![Example 29](demo/doc/screenshots/bootstrap/readme/29_example.png "Example 29")
478
855
  ```erb
479
856
  <%= f.submit %>
480
857
  ```
481
858
 
859
+ This generates:
860
+
861
+ ```html
862
+ <input class="btn btn-secondary" data-disable-with="Create User" name="commit" type="submit" value="Create User">
863
+ ```
864
+
482
865
  You can also use the `primary` helper, which adds `btn btn-primary` to your
483
866
  submit button:
484
867
 
868
+ ![Example 30](demo/doc/screenshots/bootstrap/readme/30_example.png "Example 30")
485
869
  ```erb
486
870
  <%= f.primary "Optional Label" %>
487
871
  ```
488
872
 
873
+ This generates:
874
+
875
+ ```html
876
+ <input class="btn btn-primary" data-disable-with="Optional Label" name="commit" type="submit" value="Optional Label">
877
+ ```
878
+
489
879
  You can specify your own classes like this:
490
880
 
881
+ ![Example 31](demo/doc/screenshots/bootstrap/readme/31_example.png "Example 31")
491
882
  ```erb
492
883
  <%= f.submit "Log In", class: "btn btn-success" %>
493
884
  ```
494
885
 
886
+ This generates:
887
+
888
+ ```html
889
+ <input class="btn btn-success" data-disable-with="Log In" name="commit" type="submit" value="Log In">
890
+ ```
891
+
495
892
  If the `primary` helper receives a `render_as_button: true` option or a block,
496
893
  it will be rendered as an HTML button, instead of an input tag. This allows you
497
894
  to specify HTML content and styling for your buttons (such as adding
498
895
  illustrative icons to them). For example, the following statements
499
896
 
897
+ ![Example 32](demo/doc/screenshots/bootstrap/readme/32_example.png "Example 32")
500
898
  ```erb
501
899
  <%= f.primary "Save changes <span class='fa fa-save'></span>".html_safe, render_as_button: true %>
502
900
 
@@ -506,6 +904,17 @@ illustrative icons to them). For example, the following statements
506
904
  end %>
507
905
  ```
508
906
 
907
+ This generates:
908
+
909
+ ```html
910
+ <button class="btn btn-primary" name="button" type="submit">Save changes <span class="fa fa-save">
911
+ </span>
912
+ </button>
913
+ <button class="btn btn-primary" name="button" type="submit">Save changes <span class="fa fa-save">
914
+ </span>
915
+ </button>
916
+ ```
917
+
509
918
  are equivalent, and each of them both be rendered as:
510
919
 
511
920
  ```html
@@ -519,6 +928,7 @@ Bootstrap classes), or for element targeting via CSS classes.
519
928
  Be aware, however, that using the `class` option will discard any extra classes
520
929
  you add. As an example, the following button declarations
521
930
 
931
+ ![Example 33](demo/doc/screenshots/bootstrap/readme/33_example.png "Example 33")
522
932
  ```erb
523
933
  <%= f.primary "My Nice Button", extra_class: 'my-button' %>
524
934
 
@@ -528,9 +938,8 @@ you add. As an example, the following button declarations
528
938
  will be rendered as
529
939
 
530
940
  ```html
531
- <input type="submit" value="My Nice Button" class="btn btn-primary my-button" />
532
-
533
- <input type="submit" value="My Button" class="my-button" />
941
+ <input class="btn btn-primary my-button" data-disable-with="My Nice Button" name="commit" type="submit" value="My Nice Button">
942
+ <input class="my-button" data-disable-with="My Button" name="commit" type="submit" value="My Button">
534
943
  ```
535
944
 
536
945
  (some unimportant HTML attributes have been removed for simplicity)
@@ -539,6 +948,7 @@ will be rendered as
539
948
 
540
949
  If you're using Rails 6, `bootstrap_form` supports the `rich_text_area` helper.
541
950
 
951
+ ![Example 34](demo/doc/screenshots/bootstrap/readme/34_example.png "Example 34")
542
952
  ```erb
543
953
  <%= f.rich_text_area(:life_story) %>
544
954
  ```
@@ -548,8 +958,47 @@ will be rendered as:
548
958
  ```html
549
959
  <div class="mb-3">
550
960
  <label class="form-label" for="user_life_story">Life story</label>
551
- <input type="hidden" name="user[life_story]" id="user_life_story_trix_input_user"/>
552
- <trix-editor id="user_life_story" data-blob-url-template="http://test.host/rails/active_storage/blobs/:signed_id/:filename" data-direct-upload-url="http://test.host/rails/active_storage/direct_uploads" input="user_life_story_trix_input_user" class="trix-content form-control"/>
961
+ <input autocomplete="off" id="user_life_story_trix_input_user" name="user[life_story]" type="hidden">
962
+ <trix-toolbar id="trix-toolbar-1">
963
+ <div class="trix-button-row">
964
+ <span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools">
965
+ <button class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" tabindex="-1" title="Bold" type="button">Bold</button>
966
+ <button class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" tabindex="-1" title="Italic" type="button">Italic</button>
967
+ <button class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" tabindex="-1" title="Strikethrough" type="button">Strikethrough</button>
968
+ <button class="trix-button trix-button--icon trix-button--icon-link" data-trix-action="link" data-trix-attribute="href" data-trix-key="k" tabindex="-1" title="Link" type="button">Link</button>
969
+ </span>
970
+ <span class="trix-button-group trix-button-group--block-tools" data-trix-button-group="block-tools">
971
+ <button class="trix-button trix-button--icon trix-button--icon-heading-1" data-trix-attribute="heading1" tabindex="-1" title="Heading" type="button">Heading</button>
972
+ <button class="trix-button trix-button--icon trix-button--icon-quote" data-trix-attribute="quote" tabindex="-1" title="Quote" type="button">Quote</button>
973
+ <button class="trix-button trix-button--icon trix-button--icon-code" data-trix-attribute="code" tabindex="-1" title="Code" type="button">Code</button>
974
+ <button class="trix-button trix-button--icon trix-button--icon-bullet-list" data-trix-attribute="bullet" tabindex="-1" title="Bullets" type="button">Bullets</button>
975
+ <button class="trix-button trix-button--icon trix-button--icon-number-list" data-trix-attribute="number" tabindex="-1" title="Numbers" type="button">Numbers</button>
976
+ <button class="trix-button trix-button--icon trix-button--icon-decrease-nesting-level" data-trix-action="decreaseNestingLevel" tabindex="-1" title="Decrease Level" type="button">Decrease Level</button>
977
+ <button class="trix-button trix-button--icon trix-button--icon-increase-nesting-level" data-trix-action="increaseNestingLevel" tabindex="-1" title="Increase Level" type="button">Increase Level</button>
978
+ </span>
979
+ <span class="trix-button-group trix-button-group--file-tools" data-trix-button-group="file-tools">
980
+ <button class="trix-button trix-button--icon trix-button--icon-attach" data-trix-action="attachFiles" tabindex="-1" title="Attach Files" type="button">Attach Files</button>
981
+ </span>
982
+ <span class="trix-button-group-spacer">
983
+ </span>
984
+ <span class="trix-button-group trix-button-group--history-tools" data-trix-button-group="history-tools">
985
+ <button class="trix-button trix-button--icon trix-button--icon-undo" data-trix-action="undo" data-trix-key="z" tabindex="-1" title="Undo" type="button">Undo</button>
986
+ <button class="trix-button trix-button--icon trix-button--icon-redo" data-trix-action="redo" data-trix-key="shift+z" tabindex="-1" title="Redo" type="button">Redo</button>
987
+ </span>
988
+ </div>
989
+ <div class="trix-dialogs" data-trix-dialogs="">
990
+ <div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href">
991
+ <div class="trix-dialog__link-fields">
992
+ <input aria-label="URL" class="trix-input trix-input--dialog" data-trix-input="" disabled name="href" placeholder="Enter a URL…" required="" type="url">
993
+ <div class="trix-button-group">
994
+ <input class="trix-button trix-button--dialog" data-trix-method="setAttribute" type="button" value="Link">
995
+ <input class="trix-button trix-button--dialog" data-trix-method="removeAttribute" type="button" value="Unlink">
996
+ </div>
997
+ </div>
998
+ </div>
999
+ </div>
1000
+ </trix-toolbar>
1001
+ <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">
553
1002
  </trix-editor>
554
1003
  </div>
555
1004
  ```
@@ -567,10 +1016,17 @@ The `hidden_field` helper in `bootstrap_form` calls the Rails helper directly, a
567
1016
  If you want to use the original Rails form helpers for a particular field,
568
1017
  append `_without_bootstrap` to the helper:
569
1018
 
1019
+ ![Example 35](demo/doc/screenshots/bootstrap/readme/35_example.png "Example 35")
570
1020
  ```erb
571
1021
  <%= f.text_field_without_bootstrap :email %>
572
1022
  ```
573
1023
 
1024
+ This generates:
1025
+
1026
+ ```html
1027
+ <input id="user_email" name="user[email]" type="text" value="steve@example.com">
1028
+ ```
1029
+
574
1030
  ## Form Styles
575
1031
 
576
1032
  By default, your forms will stack labels on top of controls and your controls
@@ -582,6 +1038,7 @@ To use an inline-layout form, use the `layout: :inline` option. To hide labels,
582
1038
  use the `hide_label: true` option, which keeps your labels accessible to those
583
1039
  using screen readers.
584
1040
 
1041
+ ![Example 36](demo/doc/screenshots/bootstrap/readme/36_example.png "Example 36")
585
1042
  ```erb
586
1043
  <%= bootstrap_form_for(@user, layout: :inline) do |f| %>
587
1044
  <%= f.email_field :email, hide_label: true %>
@@ -591,12 +1048,44 @@ using screen readers.
591
1048
  <% end %>
592
1049
  ```
593
1050
 
1051
+ This generates:
1052
+
1053
+ ```html
1054
+ <form accept-charset="UTF-8" action="/users" class="new_user row row-cols-auto g-3 align-items-center" id="new_user" method="post">
1055
+ <div class="col">
1056
+ <label class="form-label visually-hidden mr-sm-2 required" for="user_email">Email</label>
1057
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
1058
+ </div>
1059
+ <div class="col">
1060
+ <label class="form-label visually-hidden mr-sm-2" for="user_password">Password</label>
1061
+ <input class="form-control" id="user_password" name="user[password]" type="password">
1062
+ </div>
1063
+ <div class="form-check form-check-inline mb-3">
1064
+ <input autocomplete="off" name="user[remember_me]" type="hidden" value="0">
1065
+ <input class="form-check-input" id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
1066
+ <label class="form-check-label" for="user_remember_me">Remember me</label>
1067
+ </div>
1068
+ <div class="col">
1069
+ <input class="btn btn-secondary" data-disable-with="Create User" name="commit" type="submit" value="Create User">
1070
+ </div>
1071
+ </form>
1072
+ ```
1073
+
594
1074
  To skip label rendering at all, use `skip_label: true` option.
595
1075
 
1076
+ ![Example 37](demo/doc/screenshots/bootstrap/readme/37_example.png "Example 37")
596
1077
  ```erb
597
1078
  <%= f.password_field :password, skip_label: true %>
598
1079
  ```
599
1080
 
1081
+ This generates:
1082
+
1083
+ ```html
1084
+ <div class="mb-3">
1085
+ <input class="form-control" id="user_password" name="user[password]" type="password">
1086
+ </div>
1087
+ ```
1088
+
600
1089
  ### Horizontal Forms
601
1090
 
602
1091
  To use a horizontal-layout form with labels to the left of the control, use the
@@ -606,6 +1095,7 @@ To use a horizontal-layout form with labels to the left of the control, use the
606
1095
  In the example below, the checkbox and submit button have been wrapped in a
607
1096
  `form_group` to keep them properly aligned.
608
1097
 
1098
+ ![Example 38](demo/doc/screenshots/bootstrap/readme/38_example.png "Example 38")
609
1099
  ```erb
610
1100
  <%= bootstrap_form_for(@user, layout: :horizontal, label_col: "col-sm-2", control_col: "col-sm-10") do |f| %>
611
1101
  <%= f.email_field :email %>
@@ -619,8 +1109,43 @@ In the example below, the checkbox and submit button have been wrapped in a
619
1109
  <% end %>
620
1110
  ```
621
1111
 
1112
+ This generates:
1113
+
1114
+ ```html
1115
+ <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1116
+ <div class="mb-3 row">
1117
+ <label class="form-label col-form-label col-sm-2 required" for="user_email">Email</label>
1118
+ <div class="col-sm-10">
1119
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
1120
+ </div>
1121
+ </div>
1122
+ <div class="mb-3 row">
1123
+ <label class="form-label col-form-label col-sm-2" for="user_password">Password</label>
1124
+ <div class="col-sm-10">
1125
+ <input class="form-control" id="user_password" name="user[password]" type="password">
1126
+ </div>
1127
+ </div>
1128
+ <div class="mb-3 row">
1129
+ <div class="col-sm-10 offset-sm-2">
1130
+ <div class="form-check">
1131
+ <input autocomplete="off" name="user[remember_me]" type="hidden" value="0">
1132
+ <input class="form-check-input" id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
1133
+ <label class="form-check-label" for="user_remember_me">Remember me</label>
1134
+ </div>
1135
+ </div>
1136
+ </div>
1137
+
1138
+ <div class="mb-3 row">
1139
+ <div class="col-sm-10 offset-sm-2">
1140
+ <input class="btn btn-secondary" data-disable-with="Create User" name="commit" type="submit" value="Create User">
1141
+ </div>
1142
+ </div>
1143
+ </form>
1144
+ ```
1145
+
622
1146
  The `label_col` and `control_col` css classes can also be changed per control:
623
1147
 
1148
+ ![Example 39](demo/doc/screenshots/bootstrap/readme/39_example.png "Example 39")
624
1149
  ```erb
625
1150
  <%= bootstrap_form_for(@user, layout: :horizontal) do |f| %>
626
1151
  <%= f.email_field :email %>
@@ -631,6 +1156,30 @@ The `label_col` and `control_col` css classes can also be changed per control:
631
1156
  <% end %>
632
1157
  ```
633
1158
 
1159
+ This generates:
1160
+
1161
+ ```html
1162
+ <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1163
+ <div class="mb-3 row">
1164
+ <label class="form-label col-form-label col-sm-2 required" for="user_email">Email</label>
1165
+ <div class="col-sm-10">
1166
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
1167
+ </div>
1168
+ </div>
1169
+ <div class="mb-3 row">
1170
+ <label class="form-label col-form-label col-sm-2" for="user_age">Age</label>
1171
+ <div class="col-sm-3">
1172
+ <input class="form-control" id="user_age" name="user[age]" type="text" value="42">
1173
+ </div>
1174
+ </div>
1175
+ <div class="mb-3 row">
1176
+ <div class="col-sm-10 offset-sm-2">
1177
+ <input class="btn btn-secondary" data-disable-with="Create User" name="commit" type="submit" value="Create User">
1178
+ </div>
1179
+ </div>
1180
+ </form>
1181
+ ```
1182
+
634
1183
  or default value can be changed in initializer:
635
1184
 
636
1185
  ```ruby
@@ -653,6 +1202,7 @@ end
653
1202
 
654
1203
  Control col wrapper class can be modified with `add_control_col_class`. This option will preserve column definition:
655
1204
 
1205
+ ![Example 40](demo/doc/screenshots/bootstrap/readme/40_example.png "Example 40")
656
1206
  ```erb
657
1207
  <%= bootstrap_form_for(@user, layout: :horizontal) do |f| %>
658
1208
  <%= f.email_field :email %>
@@ -663,10 +1213,35 @@ Control col wrapper class can be modified with `add_control_col_class`. This opt
663
1213
  <% end %>
664
1214
  ```
665
1215
 
1216
+ This generates:
1217
+
1218
+ ```html
1219
+ <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1220
+ <div class="mb-3 row">
1221
+ <label class="form-label col-form-label col-sm-2 required" for="user_email">Email</label>
1222
+ <div class="col-sm-10">
1223
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
1224
+ </div>
1225
+ </div>
1226
+ <div class="mb-3 row">
1227
+ <label class="form-label col-form-label col-sm-2" for="user_age">Age</label>
1228
+ <div class="col-sm-10 additional-control-col-class">
1229
+ <input class="form-control" id="user_age" name="user[age]" type="text" value="42">
1230
+ </div>
1231
+ </div>
1232
+ <div class="mb-3 row">
1233
+ <div class="col-sm-10 offset-sm-2">
1234
+ <input class="btn btn-secondary" data-disable-with="Create User" name="commit" type="submit" value="Create User">
1235
+ </div>
1236
+ </div>
1237
+ </form>
1238
+ ```
1239
+
666
1240
  ### Custom Field Layout
667
1241
 
668
1242
  The form-level `layout` can be overridden per field, unless the form-level layout was `inline`:
669
1243
 
1244
+ ![Example 41](demo/doc/screenshots/bootstrap/readme/41_example.png "Example 41")
670
1245
  ```erb
671
1246
  <%= bootstrap_form_for(@user, layout: :horizontal) do |f| %>
672
1247
  <%= f.email_field :email %>
@@ -678,12 +1253,39 @@ The form-level `layout` can be overridden per field, unless the form-level layou
678
1253
  <% end %>
679
1254
  ```
680
1255
 
1256
+ This generates:
1257
+
1258
+ ```html
1259
+ <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1260
+ <div class="mb-3 row">
1261
+ <label class="form-label col-form-label col-sm-2 required" for="user_email">Email</label>
1262
+ <div class="col-sm-10">
1263
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
1264
+ </div>
1265
+ </div>
1266
+ <div class="mb-3">
1267
+ <label class="form-label" for="user_feet">Feet</label>
1268
+ <input class="form-control" id="user_feet" name="user[feet]" type="text" value="5">
1269
+ </div>
1270
+ <div class="mb-3">
1271
+ <label class="form-label" for="user_inches">Inches</label>
1272
+ <input class="form-control" id="user_inches" name="user[inches]" type="text" value="7">
1273
+ </div>
1274
+ <div class="mb-3 row">
1275
+ <div class="col-sm-10 offset-sm-2">
1276
+ <input class="btn btn-secondary" data-disable-with="Create User" name="commit" type="submit" value="Create User">
1277
+ </div>
1278
+ </div>
1279
+ </form>
1280
+ ```
1281
+
681
1282
  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.
682
1283
 
683
1284
  ### Custom Form Element Styles
684
1285
 
685
1286
  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:
686
1287
 
1288
+ ![Example 42](demo/doc/screenshots/bootstrap/readme/42_example.png "Example 42")
687
1289
  ```erb
688
1290
  <%= bootstrap_form_for(@user) do |f| %>
689
1291
  <%= f.email_field :email %>
@@ -693,11 +1295,33 @@ The `custom` option can be used to replace the browser default styles for check
693
1295
  <% end %>
694
1296
  ```
695
1297
 
1298
+ This generates:
1299
+
1300
+ ```html
1301
+ <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1302
+ <div class="mb-3">
1303
+ <label class="form-label required" for="user_email">Email</label>
1304
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
1305
+ </div>
1306
+ <div class="mb-3">
1307
+ <label class="form-label" for="user_password">Password</label>
1308
+ <input class="form-control" id="user_password" name="user[password]" type="password">
1309
+ </div>
1310
+ <div class="form-check mb-3">
1311
+ <input autocomplete="off" name="user[remember_me]" type="hidden" value="0">
1312
+ <input class="form-check-input" custom="true" id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
1313
+ <label class="form-check-label" for="user_remember_me">Remember me</label>
1314
+ </div>
1315
+ <input class="btn btn-secondary" data-disable-with="Log In" name="commit" type="submit" value="Log In">
1316
+ </form>
1317
+ ```
1318
+
696
1319
  ### Floating Labels
697
1320
 
698
1321
  The `floating` option can be used to enable Bootstrap 5's floating labels. This option is supported on text fields
699
1322
  and dropdowns. Here's an example:
700
1323
 
1324
+ ![Example 43](demo/doc/screenshots/bootstrap/readme/43_example.png "Example 43")
701
1325
  ```erb
702
1326
  <%= bootstrap_form_for(@user) do |f| %>
703
1327
  <%= f.email_field :email, floating: true %>
@@ -708,6 +1332,34 @@ and dropdowns. Here's an example:
708
1332
  <% end %>
709
1333
  ```
710
1334
 
1335
+ This generates:
1336
+
1337
+ ```html
1338
+ <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1339
+ <div class="mb-3 form-floating">
1340
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" placeholder="Email" required="required" type="email" value="steve@example.com">
1341
+ <label class="form-label required" for="user_email">Email</label>
1342
+ </div>
1343
+ <div class="mb-3 form-floating">
1344
+ <input class="form-control" id="user_password" name="user[password]" placeholder="Password" type="password">
1345
+ <label class="form-label" for="user_password">Password</label>
1346
+ </div>
1347
+ <div class="mb-3 form-floating">
1348
+ <input class="form-control" id="user_password" name="user[password]" placeholder="Password" type="password">
1349
+ <label class="form-label" for="user_password">Password</label>
1350
+ </div>
1351
+ <div class="mb-3 form-floating">
1352
+ <select class="form-select" id="user_status" name="user[status]">
1353
+ <option value="">Select a value</option>
1354
+ <option value="1">Active</option>
1355
+ <option value="2">Inactive</option>
1356
+ </select>
1357
+ <label class="form-label" for="user_status">Status</label>
1358
+ </div>
1359
+ <input class="btn btn-secondary" data-disable-with="Log In" name="commit" type="submit" value="Log In">
1360
+ </form>
1361
+ ```
1362
+
711
1363
  ## Validation and Errors
712
1364
 
713
1365
  Rails normally wraps fields with validation errors in a `div.field_with_errors`, but this behaviour isn't consistent with Bootstrap 4 styling. By default, `bootstrap_form` generations in-line errors which appear below the field. But it can also generate errors on the label, or not display any errors, leaving it up to you.
@@ -759,77 +1411,115 @@ To display an error message with an error summary, you can use the
759
1411
  `alert_message` helper. This won't output anything unless a model validation
760
1412
  has failed.
761
1413
 
1414
+ ![Example 44](demo/doc/screenshots/bootstrap/readme/44_example.png "Example 44")
762
1415
  ```erb
763
- <%= f.alert_message "Please fix the errors below." %>
1416
+ <%= bootstrap_form_for @user_with_error do |f| %>
1417
+ <%= f.alert_message "Please fix the errors below." %>
1418
+ <% end %>
764
1419
  ```
765
1420
 
766
1421
  Which outputs:
767
1422
 
768
1423
  ```html
769
- <div class="alert alert-danger">
770
- <p>Please fix the errors below.</p>
771
- <ul class="rails-bootstrap-forms-error-summary">
772
- <li>Email can't be blank</li>
773
- </ul>
774
- </div>
1424
+ <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1425
+ <div class="alert alert-danger">
1426
+ <p>Please fix the errors below.</p>
1427
+ <ul class="rails-bootstrap-forms-error-summary">
1428
+ <li>Email is invalid</li>
1429
+ <li>Misc is invalid</li>
1430
+ </ul>
1431
+ </div>
1432
+ </form>
775
1433
  ```
776
1434
 
777
1435
  You can turn off the error summary like this:
778
1436
 
1437
+ ![Example 45](demo/doc/screenshots/bootstrap/readme/45_example.png "Example 45")
779
1438
  ```erb
780
- <%= f.alert_message "Please fix the errors below.", error_summary: false %>
1439
+ <%= bootstrap_form_for @user_with_error do |f| %>
1440
+ <%= f.alert_message "Please fix the errors below.", error_summary: false %>
1441
+ <% end %>
1442
+ ```
1443
+
1444
+ This generates:
1445
+
1446
+ ```html
1447
+ <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1448
+ <div class="alert alert-danger">Please fix the errors below.</div>
1449
+ </form>
781
1450
  ```
782
1451
 
783
1452
  To output a simple unordered list of errors, use the `error_summary` helper.
784
1453
 
1454
+ ![Example 46](demo/doc/screenshots/bootstrap/readme/46_example.png "Example 46")
785
1455
  ```erb
786
- <%= f.error_summary %>
1456
+ <%= bootstrap_form_for @user_with_error do |f| %>
1457
+ <%= f.error_summary %>
1458
+ <% end %>
787
1459
  ```
788
1460
 
789
1461
  Which outputs:
790
1462
 
791
1463
  ```html
792
- <ul class="rails-bootstrap-forms-error-summary">
793
- <li>Email can't be blank</li>
794
- </ul>
1464
+ <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1465
+ <ul class="rails-bootstrap-forms-error-summary">
1466
+ <li>Email is invalid</li>
1467
+ <li>Misc is invalid</li>
1468
+ </ul>
1469
+ </form>
795
1470
  ```
796
1471
 
797
1472
  ### Errors On
798
1473
 
799
1474
  If you want to display a custom inline error for a specific attribute not represented by a form field, use the `errors_on` helper.
800
1475
 
1476
+ ![Example 47](demo/doc/screenshots/bootstrap/readme/47_example.png "Example 47")
801
1477
  ```erb
802
- <%= f.errors_on :tasks %>
1478
+ <%= bootstrap_form_for @user_with_error do |f| %>
1479
+ <%= f.errors_on :email %>
1480
+ <% end %>
803
1481
  ```
804
1482
 
805
1483
  Which outputs:
806
1484
 
807
1485
  ```html
808
- <div class="invalid-feedback">Tasks can't be blank.</div>
1486
+ <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1487
+ <div class="invalid-feedback">Email is invalid</div>
1488
+ </form>
809
1489
  ```
810
1490
 
811
1491
  You can hide the attribute name like this:
812
1492
 
1493
+ ![Example 48](demo/doc/screenshots/bootstrap/readme/48_example.png "Example 48")
813
1494
  ```erb
814
- <%= f.errors_on :tasks, hide_attribute_name: true %>
1495
+ <%= bootstrap_form_for @user_with_error do |f| %>
1496
+ <%= f.errors_on :email, hide_attribute_name: true %>
1497
+ <% end %>
815
1498
  ```
816
1499
 
817
1500
  Which outputs:
818
1501
 
819
1502
  ```html
820
- <div class="invalid-feedback">can't be blank.</div>
1503
+ <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1504
+ <div class="invalid-feedback">is invalid</div>
1505
+ </form>
821
1506
  ```
822
1507
 
823
1508
  You can also use a custom class for the wrapping div, like this:
824
1509
 
1510
+ ![Example 49](demo/doc/screenshots/bootstrap/readme/49_example.png "Example 49")
825
1511
  ```erb
826
- <%= f.errors_on :tasks, custom_class: 'custom-error' %>
1512
+ <%= bootstrap_form_for @user_with_error do |f| %>
1513
+ <%= f.errors_on :email, custom_class: 'custom-error' %>
1514
+ <% end %>
827
1515
  ```
828
1516
 
829
1517
  Which outputs:
830
1518
 
831
1519
  ```html
832
- <div class="custom-error">can't be blank.</div>
1520
+ <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1521
+ <div class="custom-error">Email is invalid</div>
1522
+ </form>
833
1523
  ```
834
1524
 
835
1525
  ## Required Fields
@@ -852,11 +1542,72 @@ ActiveModel::Validations::PresenceValidator.
852
1542
 
853
1543
  In cases where this behaviour is undesirable, use the `required` option to force the class to be present or absent:
854
1544
 
1545
+ ![Example 50](demo/doc/screenshots/bootstrap/readme/50_example.png "Example 50")
855
1546
  ```erb
856
1547
  <%= f.password_field :login, label: "New Username", required: true %>
857
1548
  <%= f.password_field :password, label: "New Password", required: false %>
858
1549
  ```
859
1550
 
1551
+ This generates:
1552
+
1553
+ ```html
1554
+ <div class="mb-3">
1555
+ <label class="form-label required" for="user_login">New Username</label>
1556
+ <input aria-required="true" class="form-control" id="user_login" name="user[login]" required="required" type="password">
1557
+ </div>
1558
+ <div class="mb-3">
1559
+ <label class="form-label" for="user_password">New Password</label>
1560
+ <input class="form-control" id="user_password" name="user[password]" type="password">
1561
+ </div>
1562
+ ```
1563
+
1564
+ ### Required belongs_to associations
1565
+
1566
+ Adding a form control for a `belongs_to` field will automatically pick up the associated presence validator.
1567
+
1568
+ ![Example 51](demo/doc/screenshots/bootstrap/readme/51_example.png "Example 51")
1569
+ ```erb
1570
+ <%= bootstrap_form_for(@address, url: '/address') do |f| %>
1571
+ <%= f.collection_select :user_id, @users, :id, :email, include_blank: "Select a value" %>
1572
+ <%= f.text_field :street %>
1573
+ <%= f.text_field :city %>
1574
+ <%= f.text_field :state %>
1575
+ <%= f.text_field :zip_code %>
1576
+ <%= f.submit "Save" %>
1577
+ <% end %>
1578
+ ```
1579
+
1580
+ Generated HTML:
1581
+
1582
+ ```html
1583
+ <form accept-charset="UTF-8" action="/address" class="new_address" id="new_address_1" method="post">
1584
+ <div class="mb-3">
1585
+ <label class="form-label required" for="address_user_id">User</label>
1586
+ <select class="form-select" id="address_user_id" name="address[user_id]">
1587
+ <option value="">Select a value</option>
1588
+ <option value="">steve@example.com</option>
1589
+ </select>
1590
+ </div>
1591
+ <div class="mb-3">
1592
+ <label class="form-label" for="address_street">Street</label>
1593
+ <input class="form-control" id="address_street" name="address[street]" type="text" value="Foo">
1594
+ </div>
1595
+ <div class="mb-3">
1596
+ <label class="form-label" for="address_city">City</label>
1597
+ <input class="form-control" id="address_city" name="address[city]" type="text">
1598
+ </div>
1599
+ <div class="mb-3">
1600
+ <label class="form-label" for="address_state">State</label>
1601
+ <input class="form-control" id="address_state" name="address[state]" type="text">
1602
+ </div>
1603
+ <div class="mb-3">
1604
+ <label class="form-label" for="address_zip_code">Zip code</label>
1605
+ <input class="form-control" id="address_zip_code" name="address[zip_code]" type="text">
1606
+ </div>
1607
+ <input class="btn btn-secondary" data-disable-with="Save" name="commit" type="submit" value="Save">
1608
+ </form>
1609
+ ```
1610
+
860
1611
  ## Internationalization
861
1612
 
862
1613
  bootstrap_form follows standard rails conventions so it's i18n-ready. See more