Result
The surface a flow ends on: what just happened, what to do next, and the action that follows from it.
@luc/uiExamples
The page a flow ends on
`titleAs="p"` here because the specimen is a block on a documentation page; a real page leaves the default, and the Result *is* the `h1`.
Import finished
1,284 bars were written for BTCUSDT 1h, and the series is ready to chart.
<Result
status="success"
title={t("import.finished.title")}
description={t("import.finished.body")}
extra={<Button variant="primary">Open the dataset</Button>}
/>Every status
Five tones and the text-only variant: `empty` with `icon={null}` is how a not-found outcome is said without a red circle above it.
Validated
All seven domains matched.
Failed
The provider returned 503.
Partly loaded
Two rows were skipped.
Queued
Starts when the window opens.
No results
Widen the date range.
Not found
The link may be old.
<Result status="success" title="Validated" description="All seven domains matched." />
<Result status="error" title="Failed" description="The provider returned 503." />
<Result status="empty" icon={null} title="Not found" description="The link may be old." />Compact, inside a panel
`size="sm"` is the dialog-or-panel shape, and `titleAs="h3"` keeps the outline honest inside a page that already has an `h1` and an `h2`.
Validation
Two rows were skipped
They carried a timestamp outside the contract's range.
<Result
size="sm"
status="warning"
titleAs="h3"
title="Two rows were skipped"
extra={<Button size="sm">Open the log</Button>}
/>More than a sentence
`children` is the body for an outcome that owes the reader more than a paragraph — and the two actions are where the choice actually is.
The import could not finish
Provider B refused six requests, which left the dataset partly written.
Rows already written stay where they are: the retry continues from the first missing batch rather than starting again.
<Result status="error" size="sm" title="The import could not finish" description="…">
<Text>Rows already written stay where they are.</Text>
</Result>Long copy, narrow column
The description is capped at 58 characters per line by the component, so a long sentence stays readable at 390 px.
Your export is queued behind two other jobs
The scheduler runs one export per workspace at a time, and this one is third in line. You can leave the page — the artifact is written under luc-data/research and linked from your notifications when it lands.
<Result size="sm" status="info" title="Your export is queued behind two other jobs" description="…" />Usage
import { Result } from "@luc/ui";<Result
status="success"
title="Import finished"
description="1,284 bars were written for BTCUSDT 1h."
extra={<Button>Open the dataset</Button>}
/>`titleAs` defaults to `h1` because a Result usually *is* the page; inside a card or a dialog, say `h2`, `h3` or `p`.
Package setup — peer requirements, the stylesheet and the provider — is on installation.
API
Read from the published TypeScript API, so a prop that is not listed here does not exist and a default that is listed is the one the compiler sees.
Five statuses, two sizes and a `titleAs`; `icon` overrides the mark and `icon={null}` removes it, which is what a not-found outcome usually wants.
| Export | Kind | Signature |
|---|---|---|
Result | 8 documented props | ({ className, status, title, description, icon, extra, children, size, titleAs: TitleTag, ...props }: ResultProps) => import("@types/react").JSX.Element |
Result props
Type: ResultProps
Values the compiler reads from the declaration.
| Prop | Type | Default | Notes |
|---|---|---|---|
children? | ReactNode | — | Body content for an outcome that owes the reader more than a paragraph. |
description? | ReactNode | — | |
extra? | ReactNode | — | What the reader can do next: one primary action, optionally a second. |
icon? | ReactNode | — | Override the status mark. Pass `null` for a text-only outcome — a 404 does not always want a red circle above it. |
size? | "sm" | "md" | undefined | — | `md` fills a page; `sm` sits inside a card, a dialog or a pane. |
status | ResultStatus | — | What happened. Drives the mark and its tone; the copy stays the caller's. |
title | ReactNode | — | |
titleAs? | "h2" | "h3" | "p" | "h1" | undefined | — | Heading level for the title. Defaults to `h1`, because the usual job is to be the heading of the page this outcome replaced. |
Guidelines
Do
- Use a Result for the page a flow ends on: a submitted form, a finished import, a failed payment.
- Say what happened in the title and what to do next underneath; the mark only carries the tone.
- Declare the heading level — `titleAs="h2"` inside a panel keeps the page's outline honest.
Don't
- Do not use a Result where an `EmptyState` belongs: nothing here yet is a state, not an outcome.
- Do not decorate a not-found page with a red mark; `status="empty"` or `icon={null}` says it better.
- Do not stack two Results on one page — two outcomes means two pages.
Accessibility
The mark is `aria-hidden` and the title carries the meaning, which is why the title is required and has no default copy: the component cannot translate a sentence it invented itself. `titleAs` is the caller's decision because the usual job is to *be* the page heading, while a Result inside a dialog or a card has to be a lower level. No live region is implied; when an outcome arrives after mount, `role="status"` is the caller's call.
Family
Feedback
What the product says when something happened, is happening, or did not.
10 documented entries in this family. Open the family index
Related