The exact problem: a form is technically accessible — every message is associated, announced and visible — and readers still abandon it, because every message describes the rule that failed rather than the action that would succeed.

Context and Prerequisites

This is the copy half of error summary and messaging. The wiring is assumed: messages reach the field through aria-describedby, and the summary reads the same strings. Nothing here changes any of that. What changes is what the strings say.

Message quality is the one part of the error pipeline no automated check can catch. Contrast, association and announcement are all testable; “does this sentence tell the reader what to type” is not.

The Four Properties of a Message That Works

/**
 * A message is a sentence the reader can act on. Each property below removes
 * one reason they cannot: not knowing which field, not knowing what is wrong,
 * not knowing what would be right, or not being able to see it as an error.
 */
interface Message {
  /** 1. Names the field, so it stands alone in a summary. */
  readonly subject: string;      // "Post code"
  /** 2. States what to do, in the imperative. */
  readonly action: string;       // "Enter a post code, for example M1 4AB"
  /** 3. Never blames. No "invalid", no "you must", no "error:". */
  readonly tone: 'neutral';
  /** 4. Carries meaning without colour — the text alone is enough. */
  readonly code: string;         // for analytics, not for the reader
}

Name the subject. In a summary the message appears without its field, so “Enter a value” is unusable. Post code — enter a post code, for example M1 4AB reads correctly in both places.

Say what to do. “Invalid format” describes the validator’s conclusion. “Enter a post code, for example M1 4AB” describes the reader’s next keystroke. The example is doing more work than the rule name ever could.

Do not blame. “You entered an invalid email” makes a mistake into an accusation. “Enter an address we can reach you at” is the same information with no accusation in it — and it also explains why the field exists.

Do not rely on colour. Red text with no words that indicate a problem fails for anyone who cannot distinguish it, including anyone reading in bright sunlight. The sentence itself must be recognisable as a problem.

Five common messages, and what each one becomes Invalid format becomes: post code, enter a post code, for example M1 4AB. You must enter a valid email becomes: email address, enter an address we can reach you at. Field does not match pattern becomes: card number, enter the sixteen digits on the front of the card. A message conveyed only by a red border becomes a sentence that says what is missing. And required becomes a sentence naming the field and what to put in it. Written as The problem Rewritten "Invalid format" names the rule Post code — enter one, e.g. M1 4AB "You must enter a valid email" blames the reader Email — one we can reach you at "Does not match pattern" jargon Card — the 16 digits on the front a red border, no text colour only a sentence saying what is missing "Required" no subject, no action Phone — so we can text the code Where a message lives decides how it reads A hint is shown before the reader types and describes the requirement: use twelve characters or more. It reduces the number of errors that ever happen. A message is shown after an attempt and describes the repair: your password is too short, add four more characters. It assumes the reader already tried. Writing a hint as a message produces an error that states a rule; writing a message as a hint produces a form that scolds before the reader has done anything. a hint — shown before typing describes the requirement "Use 12 characters or more" reduces how many errors happen associated with describedby, always a message — shown after an attempt describes the repair "Too short — add 4 more characters" assumes the reader already tried joins the described-by tokens, first A message that states a rule is a hint in the wrong place; a hint that scolds is a message in the wrong place.

Step-by-Step Walkthrough

  1. Write the message where the rule is. A rule and its message belong in the same place, so changing one prompts changing the other. A message table keyed by error code, far from the schema, drifts.

  2. Start with the field label. Then a dash, then the action. This reads correctly beside the field and inside the summary without a second string.

  3. Give an example for anything with a format. Post codes, card numbers, reference numbers, dates. An example removes an entire class of guessing.

  4. Explain the requirement where it is not obvious. “Phone number — so we can text you the delivery code” answers the question a required phone field always raises.

  5. Keep it to one sentence. A message that needs two sentences is usually a field that needs a hint. Hints appear before the reader types; messages appear after.

  6. Map server codes to your own copy. A rejection written for an operator does not become reader-facing just because it arrives in a detail field.

Failure Modes and Edge Cases

1. The message is longer than the answer

“Please ensure that the value entered conforms to the required format” is nineteen words to say “use DD/MM/YYYY”. Long messages are skimmed, and skimmed messages are unread.

2. The same message on every field

A generic “This field is required” repeated eight times makes a summary that says nothing eight times. Per-field wording costs a line each and makes the summary a map rather than a wall.

3. Blaming for a system failure

“Something went wrong with your submission” for a gateway timeout implies the reader did something. “We could not reach the service — try again” puts it where it belongs, and is also more accurate.

4. Copy that assumes sighted, sequential reading

“See above” and “the field below” are meaningless when the message is read out on its own, from a summary, or on a narrow screen where the layout has reflowed. Reference fields by their labels.

5. Translated messages with concatenated fragments

Building a message from label + " " + rule produces sentences that are ungrammatical in most languages other than English. Keep whole sentences as translatable units, with the label interpolated.

A short review pass catches most of it, and it can be done without opening the form:

Five things to grep the message table for Search for the words invalid, illegal and error, which almost always indicate a message written from the validator's point of view. Search for the word must, which usually introduces a rule rather than an action. Search for messages under about four words, which are rarely specific enough to act on. Search for duplicate strings, which mean several fields share one message and the summary will repeat it. And search for messages with no example on any field whose format is constrained. Search for What it usually means "invalid", "illegal", "error:" written from the validator's point of view "must", "you must" a rule where an action belongs under ~4 words too vague to act on duplicate strings the summary will say the same thing twice no example, on a formatted field the reader is left guessing the format None of this is automatable as a pass or fail, but all of it is findable in a minute with a search.

Verification Checklist


Related

Error Summary and Messaging

Frequently Asked Questions

Should the message go above or below the field?

Below the label and above the input, or immediately below the input — either works, as long as it is inside the element the field is described by and it does not move the input when it appears. What matters more than position is that the message is in the accessibility tree via aria-describedby, because that is what determines whether it is read at all; visual position only affects sighted readers, who will find it either way if it is close.

Is it worth writing per-field required messages?

Yes. Eight fields sharing ‘This field is required’ produce a summary that lists the same sentence eight times, which tells the reader nothing about which field to go to or why it matters. Per-field wording — ‘Phone number, so we can text you the delivery code’ — turns the summary into a map and answers the question a required field always raises.

What about messages that come from the server?

Treat the server’s wording as a fallback and map its stable code to copy you control. Server messages are written for whoever reads the logs, may be untranslated, and often leak internal vocabulary. Falling back to them when a code is unrecognised is still right — an imperfect message beats a silent failure — but the mapped copy should be what readers normally see.