AddThisFeature

Disabled State Standards

Make unavailable actions obvious and explainable rather than dim and mysterious.

moderate User Experience

What it adds

A house rule for when a control may be disabled at all, how it looks, and how the reason reaches the user.

What your agent is told to do

5
  1. 1

    Go through every disabled control in the app and classify why it is disabled: missing input, missing permission, wrong record state, or a request already in flight. Each of those calls for different treatment and different copy.

  2. 2

    Prefer letting the user act and then explaining the failure. A control disabled with no explanation forces the user to guess, and guessing usually ends with them leaving the screen.

  3. 3

    Where a control genuinely must stay unavailable, attach the reason to it in a form reachable by pointer, by keyboard focus, and by touch. A tooltip that appears only on hover is invisible to most of the people who need it.

  4. 4

    Use the platform's native disabled semantics where the control needs no explanation, so assistive technology reports the state correctly, and fall back to a control that looks unavailable but remains focusable only where the user must reach it to read why.

  5. 5

    Do not fix the contrast problem by darkening disabled text until it stops looking disabled. Keep the text legible and carry the unavailability in the fill and border instead. When a control may be disabled is owned here; its exact rest, hover, and focus appearance is enumerated by the Hover Active Focus Checklist.

Edge cases it handles

7
  • A natively disabled control cannot receive focus, so any explanation attached to it is unreachable by keyboard. If the reason matters, the control has to stay focusable and be marked unavailable instead.
  • The most consequential disabled control on a screen — the submit, the invite, the upgrade — is the one users are most often blocked by and the one that most often carries no explanation at all.
  • Disabling submit until a form is valid hides which field is wrong. Allow the submit and surface the errors, particularly on long forms where the offending field is off screen.
  • Disabled text still has to be read. Grey on grey at a contrast level nobody can meet is a legibility failure rather than a state.
  • A control disabled because a request is in flight needs a pending treatment distinct from one disabled for lack of permission: the first resolves on its own, the second never will.
  • Permissions and record states change mid-session, so a control disabled at load must re-evaluate rather than staying stale until the next reload.
  • Disabled items inside a menu or toolbar must not be silently skipped by keyboard navigation with no indication that they exist.

Definition of done

9
  • Every disabled control in the app has a classified reason behind it.
  • The reason a control is unavailable is reachable by pointer, keyboard, and touch.
  • No form submission is blocked by a disabled button where inline validation would explain the problem better.
  • Native disabled semantics are used where no explanation is needed, and focusable unavailable states where one is.
  • Disabled text remains legible and the state is carried by more than text colour.
  • In-flight, no-permission, and wrong-state reasons are visually distinguishable.
  • Disabled states re-evaluate when permissions or record state change during a session.
  • The feature matches the existing design system.
  • No existing functionality is broken.

Related features

How it works

  1. 1

    Copy the link

    Grab the Markdown instruction URL for this feature.

  2. 2

    Give it to your AI

    Paste it into Claude Code, Cursor, v0, Lovable — whatever you build with.

  3. 3

    It inspects, then implements

    Your agent reads your existing app first, then adds the feature to fit it.

Works with your stack

These instructions are written to adapt. They tell the agent to detect your framework, match your existing design system, and reuse what you already have — rather than assuming a particular stack.

Need it tighter than that? Customize the feature and tell it exactly what you're running.