Skip to content

Commit 16f1417

Browse files
authored
Form check markup v2 (#25050)
* match layout behaviors * ditch the indicator as separate element for psuedo-elements on the label * move disabled to attribute only on input * redo default inline check to support new markup * redo inline forms * clean up vars * update validation mixin to new structure * update checks in docs * linting for for/id attributes
1 parent 1315087 commit 16f1417

File tree

7 files changed

+234
-267
lines changed

7 files changed

+234
-267
lines changed

docs/4.0/components/dropdowns.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -615,8 +615,8 @@ Put a form within a dropdown menu, or make it into a dropdown menu, and use [mar
615615
<input type="password" class="form-control" id="exampleDropdownFormPassword1" placeholder="Password">
616616
</div>
617617
<div class="form-check">
618-
<label class="form-check-label">
619-
<input type="checkbox" class="form-check-input">
618+
<input type="checkbox" class="form-check-input" id="dropdownCheck">
619+
<label class="form-check-label" for="dropdownCheck">
620620
Remember me
621621
</label>
622622
</div>
@@ -639,8 +639,8 @@ Put a form within a dropdown menu, or make it into a dropdown menu, and use [mar
639639
<input type="password" class="form-control" id="exampleDropdownFormPassword2" placeholder="Password">
640640
</div>
641641
<div class="form-check">
642-
<label class="form-check-label">
643-
<input type="checkbox" class="form-check-input">
642+
<input type="checkbox" class="form-check-input" id="dropdownCheck2">
643+
<label class="form-check-label" for="dropdownCheck2">
644644
Remember me
645645
</label>
646646
</div>

docs/4.0/components/forms.md

+136-163
Large diffs are not rendered by default.

docs/4.0/migration.md

+12-1
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,21 @@ toc: true
1010

1111
While Beta 2 saw the bulk of our breaking changes during the beta phase, but we still have a few that needed to be addressed in the Beta 3 release. These changes apply if you're updating to Beta 3 from Beta 2 or any older version of Bootstrap.
1212

13+
### Miscellaneous
14+
1315
- Removed the unused `$thumbnail-transition` variable. We weren't transitioning anything, so it was just extra code.
14-
- Changed the CSS for managing multiple `background-image`s on custom form checkboxes and radios. Previously, the `.custom-control-indicator` element had the background color, gradient, and SVG icon. Customizing the background gradient meant replacing all of those every time you needed to change just one. Now, we have `.custom-control-indicator` for the fill and gradient and `.custom-control-indicator::before` handles the icon.
1516
- The npm package no longer includes any files other than our source and dist files; if you relied on them and were running our scripts via the `node_modules` folder, you should adapt your workflow.
17+
18+
### Forms
19+
20+
- Rewrote both custom and default checkboxes and radios. Now, both have matching HTML structure (outer `<div>` with sibling `<input>` and `<label>`) and the same layout styles (stacked default, inline with modifier class). This allows us to style the label based on the input's state, simplifying support for the `disabled` attribute (previously requiring a parent class) and better supporting our form validation.
21+
22+
As part of this, we've changed the CSS for managing multiple `background-image`s on custom form checkboxes and radios. Previously, the now removed `.custom-control-indicator` element had the background color, gradient, and SVG icon. Customizing the background gradient meant replacing all of those every time you needed to change just one. Now, we have `.custom-control-label::before` for the fill and gradient and `.custom-control-label::after` handles the icon.
23+
24+
To make a custom check inline, add `.custom-control-inline`.
25+
1626
- Updated selector for input-based button groups. Instead of `[data-toggle="buttons"] { }` for style and behavior, we use the `data` attribute just for JS behaviors and rely on a new `.btn-group-toggle` class for styling.
27+
1728
- Removed `.col-form-legend` in favor of a slightly improved `.col-form-label`. This way `.col-form-label-sm` and `.col-form-label-lg` can be used on `<legend>` elements with ease.
1829

1930
### Input groups

scss/_custom-forms.scss

+52-53
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@
99

1010
.custom-control {
1111
position: relative;
12-
display: inline-flex;
12+
display: block;
1313
min-height: (1rem * $line-height-base);
1414
padding-left: $custom-control-gutter;
15+
}
16+
17+
.custom-control-inline {
18+
display: inline-flex;
1519
margin-right: $custom-control-spacer-x;
1620
}
1721

@@ -20,51 +24,61 @@
2024
z-index: -1; // Put the input behind the label so it doesn't overlay text
2125
opacity: 0;
2226

23-
&:checked ~ .custom-control-indicator {
27+
&:checked ~ .custom-control-label::before {
2428
color: $custom-control-indicator-checked-color;
2529
@include gradient-bg($custom-control-indicator-checked-bg);
2630
@include box-shadow($custom-control-indicator-checked-box-shadow);
2731
}
2832

29-
&:focus ~ .custom-control-indicator {
33+
&:focus ~ .custom-control-label::before {
3034
// the mixin is not used here to make sure there is feedback
3135
box-shadow: $custom-control-indicator-focus-box-shadow;
3236
}
3337

34-
&:active ~ .custom-control-indicator {
38+
&:active ~ .custom-control-label::before {
3539
color: $custom-control-indicator-active-color;
3640
background-color: $custom-control-indicator-active-bg;
3741
@include box-shadow($custom-control-indicator-active-box-shadow);
3842
}
3943

4044
&:disabled {
41-
~ .custom-control-indicator {
42-
background-color: $custom-control-indicator-disabled-bg;
43-
}
45+
~ .custom-control-label {
46+
color: $custom-control-label-disabled-color;
4447

45-
~ .custom-control-description {
46-
color: $custom-control-description-disabled-color;
48+
&::before {
49+
background-color: $custom-control-indicator-disabled-bg;
50+
}
4751
}
4852
}
4953
}
5054

51-
// Custom indicator
55+
// Custom control indicators
5256
//
53-
// Generates a shadow element to create our makeshift checkbox/radio background.
57+
// Build the custom controls out of psuedo-elements.
5458

55-
.custom-control-indicator {
56-
position: absolute;
57-
top: (($line-height-base - $custom-control-indicator-size) / 2);
58-
left: 0;
59-
display: block;
60-
width: $custom-control-indicator-size;
61-
height: $custom-control-indicator-size;
62-
pointer-events: none;
63-
user-select: none;
64-
background-color: $custom-control-indicator-bg;
65-
@include box-shadow($custom-control-indicator-box-shadow);
59+
.custom-control-label {
60+
margin-bottom: 0;
6661

62+
// Background-color and (when enabled) gradient
6763
&::before {
64+
position: absolute;
65+
top: (($line-height-base - $custom-control-indicator-size) / 2);
66+
left: 0;
67+
display: block;
68+
width: $custom-control-indicator-size;
69+
height: $custom-control-indicator-size;
70+
pointer-events: none;
71+
content: "";
72+
user-select: none;
73+
background-color: $custom-control-indicator-bg;
74+
@include box-shadow($custom-control-indicator-box-shadow);
75+
}
76+
77+
// Foreground (icon)
78+
&::after {
79+
position: absolute;
80+
top: (($line-height-base - $custom-control-indicator-size) / 2);
81+
left: 0;
6882
display: block;
6983
width: $custom-control-indicator-size;
7084
height: $custom-control-indicator-size;
@@ -75,28 +89,31 @@
7589
}
7690
}
7791

92+
7893
// Checkboxes
7994
//
8095
// Tweak just a few things for checkboxes.
8196

8297
.custom-checkbox {
83-
.custom-control-indicator {
98+
.custom-control-label::before {
8499
@include border-radius($custom-checkbox-indicator-border-radius);
85100
}
86101

87-
.custom-control-input:checked ~ .custom-control-indicator {
88-
@include gradient-bg($custom-control-indicator-checked-bg);
89-
102+
.custom-control-input:checked ~ .custom-control-label {
90103
&::before {
104+
@include gradient-bg($custom-control-indicator-checked-bg);
105+
}
106+
&::after {
91107
background-image: $custom-checkbox-indicator-icon-checked;
92108
}
93109
}
94110

95-
.custom-control-input:indeterminate ~ .custom-control-indicator {
96-
@include gradient-bg($custom-checkbox-indicator-indeterminate-bg);
97-
@include box-shadow($custom-checkbox-indicator-indeterminate-box-shadow);
98-
111+
.custom-control-input:indeterminate ~ .custom-control-label {
99112
&::before {
113+
@include gradient-bg($custom-checkbox-indicator-indeterminate-bg);
114+
@include box-shadow($custom-checkbox-indicator-indeterminate-box-shadow);
115+
}
116+
&::after {
100117
background-image: $custom-checkbox-indicator-icon-indeterminate;
101118
}
102119
}
@@ -107,34 +124,16 @@
107124
// Tweak just a few things for radios.
108125

109126
.custom-radio {
110-
.custom-control-indicator {
127+
.custom-control-label::before {
111128
border-radius: $custom-radio-indicator-border-radius;
112129
}
113130

114-
.custom-control-input:checked ~ .custom-control-indicator {
115-
@include gradient-bg($custom-control-indicator-checked-bg);
116-
131+
.custom-control-input:checked ~ .custom-control-label {
117132
&::before {
118-
background-image: $custom-radio-indicator-icon-checked;
133+
@include gradient-bg($custom-control-indicator-checked-bg);
119134
}
120-
}
121-
}
122-
123-
124-
// Layout options
125-
//
126-
// By default radios and checkboxes are `inline-block` with no additional spacing
127-
// set. Use these optional classes to tweak the layout.
128-
129-
.custom-controls-stacked {
130-
display: flex;
131-
flex-direction: column;
132-
133-
.custom-control {
134-
margin-bottom: $custom-control-spacer-y;
135-
136-
+ .custom-control {
137-
margin-left: 0;
135+
&::after {
136+
background-image: $custom-radio-indicator-icon-checked;
138137
}
139138
}
140139
}

scss/_forms.scss

+19-32
Original file line numberDiff line numberDiff line change
@@ -207,33 +207,35 @@ select.form-control-lg {
207207
.form-check {
208208
position: relative;
209209
display: block;
210-
margin-bottom: $form-check-margin-bottom;
211-
212-
&.disabled {
213-
.form-check-label {
214-
color: $text-muted;
215-
}
216-
}
217-
}
218-
219-
.form-check-label {
220210
padding-left: $form-check-input-gutter;
221-
margin-bottom: 0; // Override default `<label>` bottom margin
222211
}
223212

224213
.form-check-input {
225214
position: absolute;
226215
margin-top: $form-check-input-margin-y;
227216
margin-left: -$form-check-input-gutter;
217+
218+
&:disabled ~ .form-check-label {
219+
color: $text-muted;
220+
}
221+
}
222+
223+
.form-check-label {
224+
margin-bottom: 0; // Override default `<label>` bottom margin
228225
}
229226

230-
// Radios and checkboxes on same line
231227
.form-check-inline {
232-
display: inline-block;
228+
display: inline-flex;
229+
align-items: center;
230+
padding-left: 0; // Override base .form-check
233231
margin-right: $form-check-inline-margin-x;
234232

235-
.form-check-label {
236-
vertical-align: middle;
233+
// Undo .form-check-input defaults and add some `margin-right`.
234+
.form-check-input {
235+
position: static;
236+
margin-top: 0;
237+
margin-right: $form-check-inline-input-margin-x;
238+
margin-left: 0;
237239
}
238240
}
239241

@@ -310,10 +312,6 @@ select.form-control-lg {
310312
align-items: center;
311313
justify-content: center;
312314
width: auto;
313-
margin-top: 0;
314-
margin-bottom: 0;
315-
}
316-
.form-check-label {
317315
padding-left: 0;
318316
}
319317
.form-check-input {
@@ -323,23 +321,12 @@ select.form-control-lg {
323321
margin-left: 0;
324322
}
325323

326-
// Custom form controls
327324
.custom-control {
328-
display: flex;
329325
align-items: center;
330326
justify-content: center;
331-
padding-left: 0;
332-
}
333-
.custom-control-indicator {
334-
position: static;
335-
display: inline-block;
336-
margin-right: $form-check-input-margin-x; // Flexbox alignment means we lose our HTML space here, so we compensate.
337-
vertical-align: text-bottom;
338327
}
339-
340-
// Re-override the feedback icon.
341-
.has-feedback .form-control-feedback {
342-
top: 0;
328+
.custom-control-label {
329+
margin-bottom: 0;
343330
}
344331
}
345332
}

scss/_variables.scss

+3-4
Original file line numberDiff line numberDiff line change
@@ -423,12 +423,12 @@ $input-transition: border-color .15s ease-in-out, box-shado
423423

424424
$form-text-margin-top: .25rem !default;
425425

426-
$form-check-margin-bottom: .5rem !default;
427426
$form-check-input-gutter: 1.25rem !default;
428-
$form-check-input-margin-y: .25rem !default;
427+
$form-check-input-margin-y: .3rem !default;
429428
$form-check-input-margin-x: .25rem !default;
430429

431430
$form-check-inline-margin-x: .75rem !default;
431+
$form-check-inline-input-margin-x: .3125rem !default;
432432

433433
$form-group-margin-bottom: 1rem !default;
434434

@@ -437,7 +437,6 @@ $input-group-addon-bg: $gray-200 !default;
437437
$input-group-addon-border-color: $input-border-color !default;
438438

439439
$custom-control-gutter: 1.5rem !default;
440-
$custom-control-spacer-y: .25rem !default;
441440
$custom-control-spacer-x: 1rem !default;
442441

443442
$custom-control-indicator-size: 1rem !default;
@@ -446,7 +445,7 @@ $custom-control-indicator-bg-size: 50% 50% !default;
446445
$custom-control-indicator-box-shadow: inset 0 .25rem .25rem rgba($black, .1) !default;
447446

448447
$custom-control-indicator-disabled-bg: $gray-200 !default;
449-
$custom-control-description-disabled-color: $gray-600 !default;
448+
$custom-control-label-disabled-color: $gray-600 !default;
450449

451450
$custom-control-indicator-checked-color: $white !default;
452451
$custom-control-indicator-checked-bg: theme-color("primary") !default;

scss/mixins/_forms.scss

+8-10
Original file line numberDiff line numberDiff line change
@@ -69,34 +69,32 @@
6969
}
7070
}
7171

72-
73-
// TODO: redo check markup lol crap
7472
.form-check-input {
7573
.was-validated &:#{$state},
7674
&.is-#{$state} {
77-
+ .form-check-label {
75+
~ .form-check-label {
7876
color: $color;
7977
}
8078
}
8179
}
8280

83-
// custom radios and checks
8481
.custom-control-input {
8582
.was-validated &:#{$state},
8683
&.is-#{$state} {
87-
~ .custom-control-indicator {
88-
background-color: lighten($color, 25%);
89-
}
90-
~ .custom-control-description {
84+
~ .custom-control-label {
9185
color: $color;
86+
87+
&::before {
88+
background-color: lighten($color, 25%);
89+
}
9290
}
9391
&:checked {
94-
~ .custom-control-indicator {
92+
~ .custom-control-label::before {
9593
@include gradient-bg(lighten($color, 10%));
9694
}
9795
}
9896
&:focus {
99-
~ .custom-control-indicator {
97+
~ .custom-control-label::before {
10098
box-shadow: 0 0 0 1px $body-bg, 0 0 0 $input-focus-width rgba($color, .25);
10199
}
102100
}

0 commit comments

Comments
 (0)