Section 2.4 already covered the form-related pseudo-classes such as :required, :invalid, and :checked, which select elements based on their state. This section fills in the other half: how to actually change the appearance of native controls such as checkboxes, radio buttons, and dropdowns.
appearance: Taking Over the Native Look
Checkboxes, radio buttons, and dropdowns are drawn by the operating system by default, so ordinary properties cannot override their styles directly. appearance: none strips away this system default look and turns the control into a "blank canvas"; after that you can freely set border, background, and other properties just like a div:
input[type="checkbox"] {
appearance: none;
width: 18px;
height: 18px;
border: 2px solid #999;
border-radius: 4px;
display: inline-grid;
place-content: center;
}
input[type="checkbox"]::before {
content: "";
width: 10px;
height: 10px;
background: teal;
clip-path: polygon(...); /* draw a checkmark with a clip path */transform: scale(0);
transition: transform .1s;
}
input[type="checkbox"]:checked::before {
transform: scale(1); /* the transition from Section 8.2, toggled by the :checked state */
}
ReminderAfter appearance: none, the browser no longer provides any default visual feedback for the checked state, so be sure to add your own :checked and :focus-visible styles, or accessibility will regress.
accent-color: Low-Cost Color Changes
If you only want checkboxes, radio buttons, progress bars, and range sliders to follow your brand color, you do not need the "tear it down and start over" approach of appearance: none — a single accent-color property lets the browser redraw the native controls with the color you specify while keeping the system's accessibility behavior:
:root {
accent-color: teal;
}
DEMO · accent-color before and after
The ::placeholder Pseudo-element
The placeholder text of an input can be given its own color and font weight through the ::placeholder pseudo-element, but note that only a limited set of properties can be set (mainly text-related properties; layout properties such as background are not supported):
Control appearance should work together with the form pseudo-classes from Section 2.4 so users can tell the current state at a glance — that matters more than merely "looking nice":
input:focus-visible {
outline: 2px solid teal;
outline-offset: 2px;
}
input:invalid:not(:placeholder-shown) {
border-color: crimson; /* only flag errors after the user has typed something, instead of turning red as soon as the page loads */
}
input:disabled {
background: #f2f2f2;
cursor: not-allowed;
}