Styling Buttons
Browsers ship every
<button> with a chunky OS-flavored default appearance: a beveled border, a gray or blue-tinted background, platform-specific padding and font. Building a consistent button component means resetting those defaults deliberately, then re-adding the states — hover, focus, active, disabled — that make a button feel alive and usable, rather than just resetting the look and stopping there.Resetting the native look
CSS
.btn {
appearance: none; /* removes native OS button rendering */
border: none;
background: none;
font: inherit; /* buttons don't inherit font by default */
padding: 0.6rem 1.25rem;
border-radius: 8px;
cursor: pointer;
color: inherit;
}Building the interactive states
A button isn't done once it has a nice default look — it needs a distinct visual response for every interaction state a user can put it in.
CSS
.btn--primary {
background: #2a6df4;
color: white;
transition: background-color 0.15s ease, transform 0.1s ease;
}
.btn--primary:hover {
background: #1d54c9;
}
.btn--primary:active {
background: #163f99;
transform: translateY(1px); /* subtle "pressed" feedback */
}
.btn--primary:disabled {
background: #a9c3f5;
color: rgba(255, 255, 255, 0.8);
cursor: not-allowed;
}
/* Visible keyboard-only focus ring — see Focus Styles below */
.btn--primary:focus-visible {
outline: 2px solid #163f99;
outline-offset: 2px;
}Warning
When you reset a button's native styling, you can accidentally reset its focus indicator along with it — many browsers draw a default focus ring as part of the same native rendering that `appearance: none` removes. Never ship a custom button with no visible focus state at all; see [Focus Styles & Keyboard Navigation](/css/focus-styles) for how to design one properly with `:focus-visible`.
Worked example: a reusable button with variants
CSS
<button class="btn btn--primary">Save changes</button>
<button class="btn btn--secondary">Cancel</button>
<button class="btn btn--danger">Delete</button>
<button class="btn btn--primary" disabled>Saving…</button>
.btn {
appearance: none;
border: 1px solid transparent;
font: inherit;
font-weight: 600;
padding: 0.6rem 1.25rem;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.15s ease, border-color 0.15s ease;
}
.btn--primary {
background: #2a6df4;
color: white;
}
.btn--primary:hover { background: #1d54c9; }
.btn--secondary {
background: white;
border-color: #ccc;
color: #1a1a1a;
}
.btn--secondary:hover { background: #f5f5f5; }
.btn--danger {
background: #d62828;
color: white;
}
.btn--danger:hover { background: #a91d1d; }
.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.btn:focus-visible {
outline: 2px solid #2a6df4;
outline-offset: 2px;
}Note
Keep hover and active styles subtle and fast (100–200ms transitions) — the goal is to confirm the interaction happened, not to draw attention to the animation itself.
Next
Design the focus ring properly with [Focus Styles & Keyboard Navigation](/css/focus-styles), and check your color choices against [Color Contrast & Readability](/css/color-contrast).