Lesson 12 / الدرس 12

States: hover, focus, disabled / الحالات: التحويم والتركيز والتعطيل

A page that never reacts feels broken. The same prefix idea as breakpoints applies to states — and one of them is not optional, because people navigate with a keyboard.

الصفحة التي لا تتفاعل أبدًا تبدو معطلة. وفكرة البادئة نفسها من نقاط التوقف تنطبق على الحالات — وواحدة منها ليست اختيارية، لأن الناس يتنقلون بلوحة المفاتيح.

Tailwind prefixes a state exactly as it prefixes a breakpoint: hover:bg-blue-700. Bootstrap mostly builds states into its components, so its buttons already darken on hover without you asking — which is convenient until you want something it did not anticipate.

StateTailwindWhen it applies
hover:hover:bg-sky-700Pointer over it — not on a touch screen
focus:focus:ring-2Reached by keyboard or clicked into
focus-visible:focus-visible:ring-2Focused BY KEYBOARD only
active:active:scale-95Being pressed right now
disabled:disabled:opacity-50The control is disabled
group-hover:group-hover:underlineAn ancestor marked group is hovered

The third row is the one worth learning properly. focus fires when you click a button too, which is why a clicked button used to keep a ring around it; focus-visible fires only for keyboard users, which is what you almost always meant.

Never remove the focus ring

WRONG      <button class="focus:outline-none">
           The keyboard user now has no idea where they are.

RIGHT      <button class="focus-visible:outline-none
                          focus-visible:ring-2 focus-visible:ring-sky-500">
           The default ring is replaced by a better one, not deleted.
This is the single most damaging thing people do with a framework, and it is one class long. Run the demonstration and press Tab repeatedly — the difference between the two rows is the difference between a usable page and an unusable one.

Hover is not available to everyone

A touch screen has no pointer hovering over anything. Anything that only appears on hover — a menu, a delete button on a card, a tooltip carrying the only explanation of an icon — simply does not exist for a phone user. Hover is for enhancement, never for the only route to something.

One Tailwind idea has no Bootstrap equivalent and is worth knowing: group. Mark a container group, then any child can respond to the container being hovered with group-hover:. That is how a whole card lifts and its title underlines when you hover anywhere on it — a pattern that otherwise needs a CSS rule you cannot express in a class.

Try it live / جرّب بنفسك

Preview / المعاينة

Check yourself / اختبر نفسك

1. What is wrong with focus:outline-none on a button?

2. What is the difference between focus and focus-visible?

3. Why should nothing important live only behind a hover?

Your task / مهمتك

Build a set of four buttons — primary, secondary, destructive and disabled — in both frameworks, with hover, focus-visible and active states on each. Then test the whole set with the keyboard only: tab through, and confirm you can always see where you are. Report anything that was invisible, and say what you did about the disabled button so it is not a dead end.

ابنِ مجموعة من أربعة أزرار — رئيسي وثانوي ومدمّر ومعطّل — في الإطارين، بحالات تحويم وتركيز مرئي وضغط على كل واحد. ثم اختبر المجموعة كلها بلوحة المفاتيح وحدها: تنقّل بـTab وتأكد أنك ترى دائمًا أين أنت. وأبلغ عن كل ما كان خفيًا، وقل ما فعلته بالزر المعطّل ليكفّ عن كونه طريقًا مسدودًا.

  • Four buttons, in both frameworks أربعة أزرار في الإطارين
  • hover, focus-visible and active on each تحويم وتركيز مرئي وضغط على كل واحد
  • Tabbed through with the keyboard, and reported تنقّل بلوحة المفاتيح، مبلَّغ عنه
  • The disabled button explains itself الزر المعطّل يشرح نفسه
How do you want to submit? / كيف تريد التسليم؟