Drawer 4: Behaviour

Open it when: you're working on forms, the states a control can be in, empty and error screens, interface wording, or what a first-time visitor sees.

What we know

Forms

  • One form can do several jobs. A booking button, a quote button and an upload-your-plans button can all open the same form, with its type already picked by the button that opened it. [our build]
  • Use labels that stay put. A placeholder is an example, not a label. Give format rules before the user submits. [impeccable]
  • Put errors inline, next to the field. Be specific, suggest a fix, and keep what the user typed. [impeccable]
  • Stop double submission: disable the button while it's working. [impeccable]
  • Never trust checks in the browser alone. Check again on the server. [impeccable]
  • On phones, inputs under 16px make iOS Safari zoom in, which breaks form layouts. [impeccable]
  • A switch is for settings that take effect at once. Anything that needs a submit uses a checkbox. [Astryx]
  • Form inputs are controlled: the value and the change handler live in your code. [Astryx]
  • Pick the control by the job. [Astryx]
    • Short text such as names, emails, search: a text input.
    • Longer text: a text area.
    • One option from a list: a dropdown.
    • Several from a known set: a checkbox dropdown, or chips you can remove.
    • Files: a file input with drag and drop and checks on type, size and count.
  • A layout component places fields but doesn't handle state or sending. Wrap it in a real <form>. [Astryx]

States

  • Every interactive control has default, hover, focus, active, disabled, loading and error states. [impeccable]
  • Use one set of state names everywhere: hover, focus, active, disabled, selected, loading, error, warning, success, info. [impeccable]
  • Keep controls consistent. If "save" looks different in two places, one is wrong. [impeccable]
  • Use skeleton placeholders for loading, not spinners in the middle of content. [impeccable]
  • Menus and pop-ups must escape their container. A dropdown inside a box that hides overflow gets cut off. Use <dialog>, the popover API, position: fixed or a portal. [impeccable]
  • Don't reach for a modal first. Use one only when the task needs interruption or locked focus. [impeccable]
  • Don't use a badge as decoration. Use it only for distinct states. [Astryx]
  • Some awesome-design-md files have a no-hover rule: they document only the default and pressed states. Their "Known Gaps" section lists hover and other states the copying never saw. [awesome-design-md]
  • Never rely on hover for anything that matters. Touch users can't hover. [impeccable]
  • Interrupted gestures: if a drag is cancelled or the window loses focus, clear the drag state. The next tap must work without a reload. [impeccable]
  • Wait about 300 ms after typing before running a search, and run scroll handlers at most about every 100 ms. [impeccable]

Empty and error screens

  • An empty screen teaches the interface. It doesn't just say "nothing here". [impeccable]
  • Every empty screen says what will be here, why it matters, how to start, and where to get help. [impeccable]
  • Empty screens differ by cause. [impeccable]
    • First use: show the value and offer a template.
    • User cleared everything: a light touch, easy to recreate.
    • No results: suggest a new search or clearing filters.
    • No permission: explain.
    • Error: offer a retry.
  • An empty screen needs a title and a next step, so the user isn't stuck. [Astryx]
  • A useful error says what failed, why (when that helps), and how to recover. No internal codes as the main message. [impeccable]
  • Match server errors to screens: 400 a validation message, 401 back to login, 403 a permission message, 404 a not-found screen, 429 a slow-down message, 500 a general error with a way to get help. [impeccable]
  • One broken part must not block the whole interface. [impeccable]
  • Test extremes: very long and very short text, emoji, right-to-left text, accents, huge numbers, a thousand items, no data. [impeccable]
  • Use logical CSS properties such as margin-inline-start, so right-to-left text lays out correctly. [impeccable]
  • Leave 30 to 40% extra room for translations. [impeccable] impeccable says German often runs 30% longer than English (asserted, no evidence shown).
  • Use the browser's Intl tools for dates, numbers and money, and a proper library for plurals. [impeccable]

Copy

  • Use the product's own words. Buttons name their action. Errors name the problem and the fix. [impeccable]
  • For each state, decide the one fact the user needs now, the next action, and the right tone. [impeccable]
  • Say each idea once. If the heading explains it, the intro adds something new or goes. [impeccable]
  • Labels say what will happen, not the gesture. Use the same word for the same thing everywhere. [impeccable]
  • Active voice: "Save changes", not "Changes will be saved". [impeccable]
  • A destructive action names the object and what happens to it. Prefer undo over a confirmation when recovery is safe. Never "Yes", "No", "OK" or "Submit" on a confirmation. [impeccable]
  • Loading text names the real job. Never fake progress. [impeccable]
  • Link text must make sense on its own. [impeccable]
  • Write whole messages that translate, not sentences stitched together from fragments. [impeccable]
  • Warmth is welcome around privacy, payment, deletion and lost access. Jokes are not. [impeccable]
  • Avoid marketing buzzwords such as streamline, empower, supercharge, world-class, cutting-edge. Say what the product literally does. [impeccable] impeccable calls these instant AI tells (asserted, no evidence shown).
  • Test copy at the target widths and at 200% zoom. Final copy is as short as it can be without losing meaning. [impeccable]

First use

  • Get people to first value fast. The job is not to teach the whole product. [impeccable]
  • Show, don't tell. Use the real product, not a separate tutorial mode. Teach one thing at a time. [impeccable]
  • Introduce one to three core ideas. Keep a tour to three to seven steps. [impeccable]
  • Supply sample data so a new user's first actions work. [impeccable]
  • Teach a feature when people need it. Empty screens are a chance to teach. [impeccable]
  • Let experienced users skip. Never hide the skip option. [impeccable]
  • Show onboarding once. Remember that it's done, and respect dismissals. [impeccable]
  • Ask for as little as possible at sign-up, and say why you need each thing. [impeccable]

Small pleasures

  • A delightful moment must belong to this product. A neighbouring product shouldn't be able to use it unchanged. [impeccable]
  • Match the celebration to the effort. A routine save should just feel certain. Never fake work to stage a flourish. [impeccable]
  • Generic whimsy is worse than plain clarity. [impeccable]

Tools in this drawer

  • Survive real data and errors: /impeccable harden <target>. Pick it before launch, when the screens only work with perfect data.
  • Rewrite interface wording: /impeccable clarify <target>. Pick it when buttons, errors or empty screens leave people unsure what to do.
  • First use and empty states: /impeccable onboard <target>. Pick it when new users stall or empty screens say "nothing here".
  • Tool: Astryx forms. Pick it when you build on React and need well-behaved form controls quickly.

Leads onward

Leads here