Focus, Hover and Disabled States People Can See
Style :focus-visible, :hover and :disabled so controls look usable, and keep focus rings instead of removing them. After this, keyboard users can tell where they are.
Course content
Sign in to save your progress.
-
Layout Without Float Hacks
-
Flexbox for Real Rows and Columns
-
CSS Grid When Flexbox Isn't Enough
-
-
-
Pages That Survive Phones
-
Responsive Layout With Media Queries That Make Sense
-
Mobile-First Without Building Everything Twice
-
Images and Typography That Scale Without Breaking
-
-
-
Components You Can Reuse
-
Navigation That Still Works on a Narrow Screen
-
Cards, Buttons and Shared Styles Across Pages
-
Custom Properties (CSS Variables) You Won't Regret
-
-
-
Forms and States That Look Finished
-
Focus, Hover and Disabled States People Can See
-
Accessible Forms: Labels, Errors and Keyboard Paths
-
-
-
Keep Layouts From Fighting You
-
Fix Overlap, Overflow and Z-Index Without Guessing
-
Organize CSS So You Can Find Things Later
-
-
- Final Check: HTML and CSS Intermediate
Skip ahead: If you already style :focus-visible, :hover and :disabled without removing outlines, skip to "Disabled means not available", then continue.
A control that only changes on hover looks fine with a mouse and invisible with a keyboard. A focus ring is not a decoration. It is how keyboard users know where they are.
Focus you can see
.btn:focus-visible {
outline: 3px solid #034bff;
outline-offset: 2px;
}
.btn:hover {
filter: brightness(1.05);
}
.btn:active {
transform: translateY(1px);
}
:focus-visible shows the ring for keyboard focus in modern browsers, and typically not for a pointer click. That is the usual compromise: visible when needed, quiet when not.
/* avoid this */
.btn:focus { outline: none; }
Removing outlines without a replacement fails real people. If the default outline clashes with your design, replace it. Do not delete it.
Hover is optional; focus is not
Phones often have no hover. Do not hide essential information behind :hover alone. Tooltips that only appear on hover need a focus or tap path too.
Disabled means not available
.btn:disabled,
.btn[aria-disabled="true"] {
opacity: 0.5;
cursor: not-allowed;
}
.btn:disabled:hover {
filter: none;
}
Disabled buttons should not look clickable. Prefer the native disabled attribute on <button>. aria-disabled is for cases where you must keep the control focusable to explain why it is blocked — then you also need the explanation in text.
💡 Tip: Check your page with Tab only. If you lose the caret and cannot tell which control is active, the focus style failed.
Common mistakes
outline: noneglobally. Instant accessibility debt.- Hover colour that fails contrast. Check both resting and hover states.
- Disabled links that still navigate. Use a button, or remove the
hrefand explain why.
Skip links
A “Skip to content” link as the first focusable control helps keyboard users bypass the header.
<a class="skip-link" href="#main">Skip to content</a>
...
<main id="main">...</main>
.skip-link {
position: absolute;
left: -999px;
top: 0;
}
.skip-link:focus {
left: 1rem;
z-index: 100;
background: #ffffff;
color: #080b0e;
padding: 0.5rem 0.75rem;
}
Here :focus (not only :focus-visible) is fine — the point is to appear when focused.
Visible disabled vs read-only
disabled removes the control from the form submission and usually from tab order. readonly keeps it focusable but not editable. Pick the one that matches the product rule. Styling both the same way confuses people.
What happens if you skip this
Keyboard users bounce. Audits fail. You will hear about it after launch, when changing the CSS is urgent and expensive.
Try it
Tab through your header and form. If any control disappears into the background when focused, fix that rule before shipping a new colour palette.
Would you accept a TV remote with no highlight on the selected button?
About
Style :focus-visible, :hover and :disabled so controls look usable, and keep focus rings instead of removing them. After this, keyboard users can tell where they are.
- Duration
- 5 min
- Last update
- 08/23/2026
Comments (0)
Sign in to commentNo comments yet.