Documentation issue with checkboxes?
Please search for duplicate or closed issues first.
Describe the issue
Looking at the documentation for checkboxes (https://picocss.com/docs/forms/checkboxes), I have two things that confuse me about the "Horizontal Stacking" section.
- why do the labels here have the
htmlForattribute rather than theforattribute? Maybe my search-fu isn't working today, but everything I can find abouthtmlForindicates that you would use this in Javascript, but not in direct HTML. - is there something I'm missing that triggers the horizontal stacking? I can't see anything that should cause these items to be horizontal while the previous example is vertical? If there is something (not having the
inputinside thelabel?), could you be more explicit what it is?
Current Behavior
The documentation is confusing.
Expected Behavior
I expected the documentation to be less confusing.
I ran into the same confusion with htmlFor. Seems the issue is that these examples are actually written as JSX and don't reflect the final HTML that's rendered. I guess JSX uses the Javascript property name htmlFor since for would be a reserved keyword in Javascript, then substitutes during rendering.
Here's an example where the JSX is written that gets rendered into the sample element in the docs. Probably it's just an oversight that the HTML examples contain JSX.
As for the horizontal versus vertical stacking, I found that a bit of a head scratcher too. It's indeed the nesting relationship between the label and the input that makes the difference. The default style for labels is display: block, but when a label is the sibling of a radio or checkbox that's overridden to display: inline-block. So the nested form prevents the sibling rule from applying.
One thing I found interesting here is that the ~ used is actually a subsequent sibling selector, which means that a label coming before the first input won't merge into the horizontal flow by default; it stays above. That behavior makes sense for a legend, but for label it strikes me as odd.
One thing I found interesting here is that the
~used is actually a subsequent sibling selector, which means that a label coming before the first input won't merge into the horizontal flow by default; it stays above. That behavior makes sense for a legend, but for label it strikes me as odd
In CSS, it's not possible to select a previous sibling (or a parent element, for that matter) so it's necessary for the <label> to come after the input. The subsequent-sibling combinator (~) matches all instances of the second element that follow the first element (not necessarily immediately), as opposed to the next-sibling combinator (+) which matches the second element only if it immediately follows the first element. There is no combinator that will match preceding siblings.
Thanks for the clarification @dev-willis. So selecting a label preceding an input would require a separate rule, perhaps using ~ but with the sibling order inverted. I can understand why this was not included, since it's standard to place radio and checkbox labels after the control. In the end I found that trying to use a label before the controls as a replacement for a legend was not a satisfactory design and so I abandoned this approach.
Well, no, it's not that it would require a separate rule: it's literally impossible to select a preceding element with CSS alone. For this reason, creating custom styles for <input> elements requires the label to follow the input, making it possible to style checked inputs with input:checked + label. The input itself is hidden and the label element is made to look like a checkbox.
it's literally impossible to select a preceding element with CSS alone
I see what you mean now. The fact of not being able to select a previous sibling is equivalent to not being able to select an element based on the fact that it has some following sibling.
However, it seems that this restriction has been lifted with has. It's now possible in modern browsers to select both parent elements and previous siblings.
Adding this rule on top of Pico did what I was looking for:
label:has(+ input) {
display: inline-block;
}
However, it seems that this restriction has been lifted with
has. It's now possible in modern browsers to select both parent elements and previous siblings.
Ah, very nice! Technically, it isn't actually selecting a previous sibling (it's looking ahead of the currently selected element) but it accomplishes the same thing. A good solution!