Outcome
Render a failed step as media, a title, a description, and the action that follows, in a card or on one line, with the words coming from the message catalog.
Every flow ends a failed step in an Outcome: what happened, what to do about it, and the retry the
flow allows. Connect.Outcome, Provision.Outcome, Cleanup.Outcome, and Verify.Outcome bind
their controller to the same parts, so a failure reads the same way everywhere.
/** The default composition, then one the host writes itself. Both take their words from the catalog. */
export function ConnectionOutcome() {
const controller = Connect.useController({ domain });
return (
<>
<Connect.Outcome controller={controller} />
<Connect.Outcome controller={controller} layout="inline">
<Outcome.Media variant="default">
<MyIcon />
</Outcome.Media>
<Outcome.Title />
<Outcome.Content />
</Connect.Outcome>
</>
);
}Usage
/** The default composition, then one the host writes itself. Both take their words from the catalog. */
export function ConnectionOutcome() {
const controller = Connect.useController({ domain });
return (
<>
<Connect.Outcome controller={controller} />
<Connect.Outcome controller={controller} layout="inline">
<Outcome.Media variant="default">
<MyIcon />
</Outcome.Media>
<Outcome.Title />
<Outcome.Content />
</Connect.Outcome>
</>
);
}Anatomy
| Part | Renders |
|---|---|
Outcome.Root |
The panel, with data-layout, data-tone, and role="alert" |
Outcome.Header |
Media, title, and description together |
Outcome.Media |
The glyph for the tone, framed (icon) or bare (default) |
Outcome.Title |
The catalog’s heading for the reason |
Outcome.Description |
The catalog’s sentence about what to do next |
Outcome.Content |
The actions, starting with the flow’s retry |
X.Outcome with no children renders that composition. With children it renders yours, and the
binding stays: Outcome.Title and Outcome.Description still read the catalog, and
Outcome.Content still holds the flow’s retry.
Layout and tone
layout="card" is a dashed panel with the media above the words, for a flow that has room.
layout="inline" puts the media, the title, and the action on one line, for the row under a form
field or beside a step in progress.
data-tone is danger for a failure and warning for a receipt that only partly landed. Each tone
draws its own glyph from icons on DomainKit.Root and colours itself from
--domainkit-danger, --domainkit-warning, and --domainkit-success. tone and layout on
Outcome.Root override what the flow resolved, and every part below reads the override.
Words
Messages.outcome(error, catalog, context) returns the { title, description } pair for a reason.
The context names the provider the customer acted on, which is what lets a rejected token read
“Cloudflare didn’t accept this token” rather than naming an HTTP status. Messages.failure returns
the same pair as one sentence, for a host that renders text rather than a card.
Override one reason on DomainKit.Root:
<DomainKit.Root
messages={{
unauthenticated: (_reason, context) => ({
title: `${context.provider ?? "That provider"} turned down the token`,
description: "Create a token with DNS edit rights and paste it again.",
}),
}}
transport={transport}
/>
Read-only
A retry is a write, so Outcome.Content renders nothing when the flow is read-only and the failure
stays on screen. Verification is the exception: observing reads the world rather than changing the
domain, so its retry stays.