opsinjs

Escalate an alert without alarming

Move a message up the escalation ladder only as far as it has earned, and spend the screen's alarm budget on the one thing that deserves it.

The task

Something has happened that the person may need to know about: a reading outside its usual range, a missed dose, a device that has stopped reporting, a result that has arrived. You have to decide how loudly to say it.

The instinct is to make important things prominent, and it is wrong in aggregate. Every product that treats prominence as free ends up with a screen where three things are shouting, and a screen where three things are shouting is a screen where nothing is. That is alarm fatigue, and it is the mechanism by which the one alert that mattered gets dismissed with the others.

The discipline is a ladder and a budget. Each message starts at the bottom of the ladder and climbs only as far as it can justify; the screen has a fixed budget at the top, and if two things want it, one of them is not going to get it.

What you need

Every rung of the ladder below is shipped: the code exists and installs, the API may change in any release, and none of it has been through an accessibility or a clinical review. What none of it does is decide which rung a message belongs on. That is the clinical rule your product owns, and it is the first step below.

PartComponentStatusWhat it does here
The quietest rungStatusPillShippedAmbient state, in place, no interruption.
The middle rungAlertBannerShippedAn in-context statement the reader must see, with a budget.
The actionCareCardShippedWhat to do and by when, at three urgency levels.
Not on the ladderCalloutShippedOrdinary information, deliberately outside the status axis.
The top rungDialog · SheetShippedInterruption. Requires a rule, not a preference.
The responseButtonShippedThe action must be reachable from the alert itself.
The boundaryDisclaimerNoteShippedWhat this alert is and is not, where the rule requires it.

Tokens, by family:

FamilyWhere it appliesReference
--opsin-status-*The pill, the banner and the care card, which are the only place the status axis appearsClinical status semantics
--opsin-category-*Never on an alert. An alert grades; it does not identifyThe two colour axes
Material rungThe banner's rung in context; the interruptive surface's rung above itLayering and elevation
MotionPresentation only, never emphasisMotion in health UI

Build it

Decide whether this is an alert at all

One question: does the reader have to do something? If not, it is information, and information goes in a Callout, which sits deliberately outside the status axis so that it cannot borrow urgency it has not earned.

"Your results are ready" is information. "Your results are ready and your clinic needs you to call before Friday" is an alert. The difference is an action with a deadline, not the importance of the subject matter.

Take the level from the clinical rule, not from the design

The four levels are steady, watch, attention and urgent. They are defined in Clinical status semantics, and they are assigned upstream of the UI. Your job is to render the level you were given, not to choose one that feels right.

If you find yourself picking a level because the banner looked insufficiently serious, stop: you are making a clinical judgement in a stylesheet.

Map the level to a rung, and no further

LevelRungSurface
steadyambientStatusPill in place. No banner.
watchambientStatusPill, plus a sentence on the detail surface. Still no banner.
attentionin-contextAlertBanner on the surface it concerns, with the action inside it.
urgentin-context, then interruptiveAlertBanner plus a CareCard with the action and its timing. Interruption only if a documented rule requires it.

Note what is not here: no rung is a toast, and no rung is a notification badge on a tab. A message that appears and vanishes is not an escalation, it is a gamble that the person was looking.

Spend the budget deliberately

One urgent surface per screen. That is the whole rule, and Alarm fatigue is the argument for it.

When a second urgent message arrives for the same screen, you do not stack them. You either aggregate them into one surface that names both, or you demote one, or you move one to a screen of its own. Which of those it is, is a product decision that somebody makes once and writes down. There is no fourth option, and "show both" is not an option.

Count attention-level surfaces too, with a soft ceiling of about two. Three amber banners is a screen the reader will learn to scroll past.

Put the action inside the alert

A banner that says something is wrong and gives no way to act on it is a source of anxiety with no outlet. Every alert at attention or above carries exactly one primary action, reachable from the alert itself, and that action is specific: "Call the clinic", "Log today's reading", "Book a repeat test". Not "Learn more".

If the honest answer is that there is nothing to do yet, say that in words: "There is nothing you need to do. Your clinic will contact you." Then drop the alert a rung, because an alert with no action is information.

Decide persistence and acknowledgement before you ship

Two symmetrical failures. An alert that cannot be dismissed becomes furniture and is stopped being seen within a week. An alert that vanishes on its own may never have been seen at all.

Decide per level: what dismisses it, whether dismissal is recorded, whether it returns, and what condition ends it for good. The end condition is usually the underlying state resolving, not the person tapping something. An alert that a tap silences while the situation continues is the more dangerous of the two failures.

Suppress repetition, not information

The same alert re-raised daily is noise; a genuinely new instance is not. Suppress by identity and state, never by count. "We have already told them three times" is not a reason to stop telling them if the state is still true and still urgent. The right lever is to change the surface, not to go silent.

The copy

The sentence shape is fixed per level. The full patterns live in Writing status and alerts; the essentials are:

  • State the fact first, in the reader's words. Not the system's: "Your blood pressure reading was higher than usual", not "Threshold exceeded".
  • Then the action and its timing. "Take another reading in the morning and log it." A deadline with no action, or an action with no deadline, is half a message.
  • Then the boundary, if the rule requires one. What this is not: not a diagnosis, not a decision, not a substitute for advice.

Do

"Your blood pressure has been above your usual range for three mornings. Book a check with your clinic in the next week." That is fact, action, timing, in that order.

Don’t

"⚠️ URGENT: ABNORMAL BP DETECTED!!" The faults are capitals and punctuation used as severity, a banned word, a machine's vocabulary, and no action at all.

Never use capitals, exclamation marks, sirens or emoji to carry severity. Severity is the status word, its icon and its surface. A design that needs typographic shouting to feel urgent has an escalation problem, not a copy problem.

Never frighten to drive compliance. Fear works once and costs the reader's trust permanently; a person who has learned that your app exaggerates will discount the alert that matters.

Emergencies are a special case and are not a banner. If a value or an answer implies immediate danger, the surface says plainly what to do right now: call emergency services, or go to hospital. It comes in the shortest sentence that can carry it, above everything else, and the rest of the screen gets out of the way. The rule for when this applies belongs to your product and is not something a component infers. See Clinical interaction guidelines.

Get it right

Safety

  • You can name the rule that assigned this level and who owns it.
  • Exactly one urgent surface exists on the screen. Count them.
  • The alert states a fact, then an action, then a boundary. Not a diagnosis.
  • The action is reachable and specific.
  • Dismissal does not resolve the underlying state, and does not pretend to.
  • No alert is raised from a single out-of-range reading unless the rule says a single reading is sufficient. See Reference ranges.
  • The alert is honest about uncertainty: if the data behind it is stale or partial, the alert says so rather than asserting a current fact. Uncertainty and staleness is the doctrine on stale and partial data.

Accessibility

  • Severity is carried by the word and the icon as well as the colour, and survives greyscale and every simulated colour-vision deficiency. Colour independence sets that bar.
  • The announcement is proportionate: an ambient status change is announced politely and does not interrupt; an interruptive surface takes focus, and only the interruptive surface may. The contract is in Screen readers.
  • Focus is never stolen at attention or below. A banner that grabs focus mid-task loses the reader's place and their typed input.
  • An interruptive surface traps focus, is dismissible with Escape, and returns focus to where it came from. See Keyboard and focus.
  • Nothing pulses, flashes or shakes. Motion never conveys urgency, at any level, and under prefers-reduced-motion the alert is simply present. Reduced motion covers that form.
  • At 200% text the alert reflows and the action stays visible with it; the action never scrolls away from the sentence that justifies it.
  • The dismiss control is a real control with a real name, at least 44pt, and is not the only way to leave the alert.

Variations

The alert arrives while the app is closed. A push notification is the same message on a surface you do not control, delivered to a lock screen somebody else may be able to read. It needs its own budget and its own privacy posture, and the in-app alert the person finds on opening must match what the notification said. A push that says more than the screen it opens is a broken promise.

Not written yet.

Off-screen alerts and their relationship to the in-app banner are not covered by any recipe or pattern yet. They are the largest real source of alarm fatigue in consumer health products.

The alert is about the system, not the person. A device that has stopped syncing, a permission that has been revoked. Use a Callout and keep it off the clinical status axis: the person is not in a clinical state because your integration broke.

Several alerts, same cause. Aggregate at the cause, not the symptom. Five missed readings is one message about a missed week.

The alert is a question. "Did you take your evening dose?" is not an alert; it is a prompt for input, and it belongs in the logging flow. Capture a daily log entry is that flow.

The reader is a carer, not the patient. The urgency is the same, the wording is not, and the privacy considerations are different. Say who the alert is about.

  • Alarm fatigue is the doctrine behind the budget, including why prominence is a scarce resource rather than a free one.
  • Alert escalation covers the same ladder at flow scale, from ambient to interruptive, with the per-session budget.
  • AlertBanner and CareCard are the two component specifications that carry the top two rungs.

On this page