I opened #23444 several weeks ago to gather feedback, but I haven't seen or heard much. This past week I put the changes to the test in this Codepen and found a simpler, more flexible path forward. Thus, I've once again rewritten the native and custom checks.
Now, both native and custom checks share the same HTML, but different classes:
<!-- Default -->
<div class="form-check">
<input type="checkbox" class="form-check-input" id="exampleCheck1">
<label class="form-check-label" for="exampleCheck1">Browser default checkbox</label>
</div>
<!-- Custom -->
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="customCheck1">
<label class="custom-control-label" for="customCheck1">Custom checkbox</label>
</div>
Here's why things have changed:
- This structure allows sibling selectors (
~
) to style the<label>
based on the<input>
state. - For form validation feedback, we can also use sibling selectors to show valid or invalid text.
- Previously, default and custom checks were vastly different in markup. They're now the same, but different classes. For custom checks, the custom indicator was previously a
<span>
—it's now generated::before
and::after
pseudo-elements. - Default and custom checks layout previously behaved differently—default being stacked, custom being inline. Now, both are the same and
.custom-controls-stacked
is no more. Inline custom checks need the.custom-control-inline
modifier, matching the defaults.
Altogether, these changes fix #23426 (closed), fix #23449 (closed), close #23503, fix #24624 (closed), fix #24888 (closed).