custom-styled input toggle

I don't mind a good challenge once in a while, but there is one thing I will usually refuse on the spot: custom-styled input fields. Not just because most forms of input fields are notoriously hard to style cross-browser, but also because most "fake" solutions mess up accessibility and are far from future-proof. In most cases, the result isn't worth the effort and you're better off leaving the styling of input fields to the browser or OS. There is one notable exception though.

toggles

The biggest problem with form elements is that they are part of the same basic package. A simple text input field may not be all that difficult to style, but a dropdown (select) is (and will continue to be until shadow dom css support becomes common across all popular browsers). Combine a styled text input field with an unstyled dropdown on the same form and the result is even more atrocious than just leaving the design to the browser or OS. So unless we're talking extremely controlled conditions, I prefer to stay away from styling input elements altogether.

A notable exception is the "toggle" element (or switch). It isn't part of the standard package of input elements anyway and it can be cooked up in a very css-friendly and accessible way. Combining it with other elements isn't all that jarring and it does look much better than the possible alternatives.

toggle markup

<div class="toggle"> <div class="label">Toggle label</div> <div class="value"> <div class="control"> <input type="radio" id="id-1" name="name" checked="checked" /> <label for="id-1">on</label> </div> <div class="control"> <input type="radio" id="id-2" name="name"/> <label for="id-2">off</label> </div> </div> </div>

The cool thing about a toggle is that structurally/semantically speaking it's little more than list of associated radio buttons. A toggle gives you a range of options (though usually limited to 2) of which you can select only one. The biggest functional difference between a toggle and classic radio button list is that a toggle usually (if not always) comes with a preselected state, where a list of radio buttons can all be deselected when loading the form.

The html snippet above may appear a little verbose to some (my code always does), but all structural elements make sense and on top of that they will prove quite helpful when applying the css. Feel free to use leaner html if the situation permits it though.

css and accessibility

.toggle .control {float:left;} .toggle .control input {.hidden; [hide from view]}

Now, the cool thing about radio buttons (and checkboxes for that matter) is that they can be controlled exclusively with their associated labels. Clicking the label will either select or deselect the associated input, which is all the interaction we need really. So hiding the actual input field and using the label as input control is perfectly safe in this case; no fancy javascript trickery required.

.toggle .control input:checked + label {[active state]} .toggle .control input:focus + label {[focus state]}

More help arrives with the option to style elements based on the checked status of a radio input. Because our actual input element is in front of its associated label, we can use the selected state of the radio input to change the style of the label (to a visually active state). The same trick helps us to style the focused state of the input (aimed at keyboard users who can activate radio buttons by pressing the 'enter' key).

check the test page for custom-styled toggles

safe, but not for everyone

When I say "safe", I mean safe for most people today. When working with the :checked pseudo selector and the + (adjacent sibling) combinator you always have to be weary of support in older browsers (fe, :checked is not supported in IE8). Then again, there are viable (and easy) javascript fixes for this and the combined percentage of people using these outdated browsers without javascript support is so small that they could be deemed infinitesimal. Even then, if you really need IE8- support you could always restyle the toggle to function as a regular radio button list using your IE hacks of choice.

If you are a structural freak like me you might not be too happy putting the radio button before the label (from a structural point of view, it makes little sense as you cannot select something of which you don't know the label). Once again, a little javascript will help you to apply the focused/active classes to the root (.toggle) should you decide to place the input field behind the label.

conclusion

Styling input elements remains a very tricky job, but when it comes to toggles I feel that the method above is solid enough to use, even sporting some proper browser fallback mechanisms. Hopefully there will come a time when the shadow dom opens up all the doors to custom styled forms, but for now I think accessibility still trumps design as form elements are often an essential part of our website. So use with care and only when you're certain you are not alienating a chunk of our audience.