Consent flow
A short sequence that asks for one scope at a time, records what was agreed to, and makes declining as easy as agreeing.
What this screen does
This is the only specimen in the set that is a sequence rather than a single surface, because consent cannot honestly be asked on one screen: there is the ask, there is the operating system's own permission prompt, and there is what the product does with the answer. That answer includes no.
The flow asks for one scope, at the moment that scope becomes useful, in words the reader can act on. It ends in one of three states: granted, declined, or partially granted, which here means yes to some of the sheets and no to others, and all three are ordinary outcomes that the product continues from.
It is also the screen where a design's honesty is most directly testable. Almost every dark pattern in health software lives here: the pre-ticked box, the grey decline link beside a filled Allow button, the wall of text with a single inviting control at the bottom. Each of them is visible in a screenshot.
What this screen deliberately does not do. It does not ask at first launch, before the person knows what they would be agreeing to. It does not bundle scopes into one accept-everything decision. It does not imitate the operating system's own prompt. It does not treat dismissal as agreement. And it does not make refusal a dead end.
Composition
No composition tree yet for consent-flow. If it turns out to be a single element rather than a compound component, say so here in a sentence. An empty tree and a deliberately flat component look identical, and only one of them is finished.
Rungs are given by position; they are named in The ladder.
ConsentFlow three states, one scope per sheet
├── 1. Ask one ConsentSheet per scope, shown when
│ │ that scope becomes useful, one rung above
│ │ the surface that triggered it
│ ├── Purpose the benefit, concretely, before the ask
│ ├── HandlingNote who else sees it · how long · how to delete
│ ├── DisclaimerNote what this consent does not cover
│ └── Answers two buttons, equal weight, equal size
│ ├── AllowAction
│ └── DeclineAction "Not now", never a grey text link
├── 1b. Ask again the next scope, only if the reader reaches
│ the moment it serves; never bundled with
│ the first into one accept-everything sheet
├── 2. PlatformPrompt the operating system's own dialog. It is
│ triggered only after Allow, never styled
│ to look like ours, never pre-empted
└── 3. Outcome page ground
├── Granted continue to the thing they wanted
├── PartiallyGranted say which asks were agreed to and which
│ were not
└── Declined EmptyState: what still works, and the way
back. It is never a wallOne scope is one sheet. ConsentSheet has no
purposes array and no per-item switch, and that is deliberate: it asks one
question so the answer means one thing. Three permissions are three sheets, each
asked when it becomes useful and each recording its own grant against its own
wording. A sheet that gathered several scopes behind individual switches would be
a product invention with no doctrine behind it, and it would need a control the
roster does not carry. Consent and disclosure
holds the reasoning. The shipped specimen of the sequence is
registry/examples/consent-sheet-two-questions-two-sheets.tsx, where the reader
grants the first scope and refuses the second.
Three composition rules this screen demonstrates:
The two answers are one component used twice. Same size, same contrast, same target. That is the whole anti-dark-pattern mechanism, and it is checkable from a screenshot in greyscale.
The explanation precedes the controls in the source order, not merely above them visually. A screen-reader user must meet what they are allowing before they meet Allow.
Declining leads somewhere. The declined outcome is a designed surface with a next step, not a modal that refuses to close. A product that punishes refusal has not asked a question.
Preview
NOT IMPLEMENTED. The opsinjs component `consent-flow` does not exist in any released version of opsinjs. There is no package to install, no module to import and no props interface to generate code against. Everything on this page is a specification of intended behaviour and may change without notice. Do not write code against it.
consent-flow is not built yet
/view/base/base-lyra/screen/consent-flow?mode=light, which renders under the product theme rather than the documentation chrome. There is nothing at that address yet.PlannedRoadmapWhat “planned” means
/view/base/base-lyra/screen/consent-flow?mode=lightSafety notes
- Nothing is collected before the answer. Not one reading "to prepare the view".
- The scope described is the scope collected. If the implementation reads more than the sentence says, the sentence is untrue whatever was intended.
- Everything starts off. A pre-ticked control is not a decision, and in most regimes it is not a consent either.
- Dismissal is not consent. Swiping the sheet away, backgrounding the app or pressing Escape all mean no answer given, and the flow may be re-entered without penalty.
- The grant is recorded against the wording version, so that the question "what exactly did this person agree to" has an answer later.
- Re-ask on a change of scope or wording, never on a timer. A periodic re-ask trains people to tap through, which destroys the meaning of the answer.
- Revocation lives in one predictable place for every scope, takes effect immediately, and says what happens to data already collected. See Consent and disclosure.
- Consent to a feature is not consent to research, marketing, or sharing with an employer or insurer. Each is a separate ask, in its own words.
- Consent given by a carer, or for a child, is a different flow with different obligations. If the product does not support it, say so rather than letting the adult flow be used on somebody else's behalf.
- No clinical status colour appears anywhere in this flow. Consent is not a clinical state. The two colour axes explains the separation.
Accessibility
Landmarks and headings. Each step has one H1 stating what is being asked. Each scope is asked on its own sheet rather than as an item in a list, and its description is programmatically associated with the answers it governs.
Reading order is the contract. Purpose, scope, handling, boundary, then the two answers. This screen fails more often on order than on anything else: an Allow button that appears early in the DOM for visual reasons puts the answer before the question for anyone not reading visually.
Focus. Focus enters the sheet on open and lands on the heading, not on Allow. Focus is trapped while the sheet is modal, Escape dismisses it, and focus returns to the control that opened it. Keyboard and focus specifies that behaviour.
Equal weight is verifiable. Render the sheet in greyscale: if one answer still dominates, the dominance was built from colour and the screen is a funnel. Colour independence is the rule it breaks.
Targets. Both answers clear 44pt with real separation between them, so that the wrong one is not tapped by accident. See Target size and motor accessibility.
Text at 200%. Both answers remain visible together. A reflow that puts Allow on screen and Decline below the fold creates a dark pattern out of a layout bug, so this is a test case rather than a nicety. Text resizing and zoom has the reflow case.
Reading level. Consent copy fails more readers than any other copy in a health product. Check it against the target in Health literacy, and expand clinical words inline with Term rather than in a footnote.
No timers. Nothing in the flow expires, auto-advances or auto-dismisses. A sheet that closes itself has taken the decision. Cognitive accessibility is where that rule lives.