appearance property
Form controls — checkboxes, radios, selects, buttons, search inputs — come with an OS-drawn default look baked in by the browser. The appearance property is the switch that turns that native rendering on or off, and it's the classic first step whenever you want to fully custom-style a control instead of just tweaking its colors.
appearance: none
appearance: none strips away the browser and OS's built-in look for the element, leaving a plain box you can style like any other element — borders, background, border-radius, custom pseudo-elements for icons or checkmarks, all become fair game.input[type="checkbox"] {
appearance: none;
width: 20px;
height: 20px;
border: 2px solid #999;
border-radius: 4px;
background: white;
}
select {
appearance: none;
padding: 0.5rem 2rem 0.5rem 0.75rem;
border: 1px solid #ccc;
border-radius: 8px;
background: white url("data:image/svg+xml,...") no-repeat right 0.75rem center;
}appearance: auto and appearance: base
appearance: auto restores the browser's default native rendering — useful when you've reset appearance globally (e.g. via a CSS reset) and want to opt a specific control back in. A newer keyword, appearance: base (seen alongside appearance: base-select for the <select> element specifically), takes a different approach: rather than throwing away native rendering entirely, it opts an element into a browser rendering path that keeps native behavior (focus handling, keyboard interaction) while exposing more of the control's internals to CSS through dedicated pseudo-elements.
/* Reset all form controls, then explicitly restore native rendering
for the ones you don't want to touch */
input, select, textarea, button {
appearance: none;
}
input[type="checkbox"] {
appearance: auto; /* keep the OS checkbox for this one control */
}Worked example: a custom checkbox
<label class="checkbox">
<input type="checkbox" />
<span class="checkbox__box"></span>
Subscribe to updates
</label>
.checkbox {
display: inline-flex;
align-items: center;
gap: 0.5rem;
cursor: pointer;
}
.checkbox input[type="checkbox"] {
appearance: none; /* remove native checkbox rendering */
margin: 0;
width: 0;
height: 0; /* the visible box is the sibling <span> instead */
}
.checkbox__box {
width: 20px;
height: 20px;
border: 2px solid #999;
border-radius: 4px;
background: white;
display: inline-block;
position: relative;
}
.checkbox input:checked + .checkbox__box {
background: #2a6df4;
border-color: #2a6df4;
}
.checkbox input:checked + .checkbox__box::after {
content: "";
position: absolute;
left: 6px;
top: 2px;
width: 5px;
height: 10px;
border: solid white;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
/* Re-implement a clearly visible focus indicator, since removing
native appearance can remove the browser's default focus ring too */
.checkbox input:focus-visible + .checkbox__box {
outline: 2px solid #2a6df4;
outline-offset: 2px;
}