/// Feedback
EmptyState
A centered, dashed-frame placeholder for a surface that legitimately has nothing to show.
import { EmptyState } from "@protocore/pds";Basics
A title and a description inside a dashed frame. The eyebrow defaults to NO DATA; override it to name the specific thing that's missing.
Nodes you provision will show up here with their health and region.
With icon and action
Add an icon for recognition and an action (usually a Button) that resolves the emptiness — the single most useful next step.
Spin up a validator to start earning protocol rewards on the ledger.
Empty vs. no results
"Nothing exists yet" and "nothing matches your filter" are different states. The first invites creation; the second offers a way back out of the filter.
Try a broader query or clear the active filters.
The five-state doctrine
EmptyState is state 2 of the five every data surface must render — *loading, empty, error, pending, data*. It means the request succeeded and the answer is genuinely nothing.
- Still fetching? That's loading — a LoadingSkeleton, not an empty state.
- Request failed? That's error — an ErrorState. Never show "No data" when you actually failed to fetch it; it hides the problem and blocks retry.
- Mutation over existing rows? That's pending — keep the data, layer a Spinner.
Getting this distinction right is the whole point of the doctrine: an empty state is an answer, not an absence of one.
Usage
Do
- Reserve EmptyState for a successful fetch that returned nothing.
- Offer one clear next action ("Provision node", "Clear filters").
- Distinguish "nothing yet" (invite creation) from "no matches" (offer escape).
- Rewrite the eyebrow and title to name the specific missing thing.
Don't
- Use EmptyState to mask a failed request — that's an ErrorState.
- Show it while data is still loading.
- Leave the generic "NO DATA" eyebrow on a user-facing screen.
- Stack multiple competing actions inside one empty state.
Accessibility
- EmptyState renders as a plain region — it is informational, not an alert, so it is not announced assertively.
- The `icon` slot is decorative and marked `aria-hidden`; meaning must live in the title and description text.
- Any `action` you pass (e.g. a Button) keeps its own semantics and keyboard behavior.
- Ensure the title conveys the state in words, never through the dashed frame or icon alone.
Mobile (React Native)
Preview. @protocore/pds-mobile ships the React Native sibling of EmptyState. It mirrors the web API where React Native allows; the package is a preview with no device-level QA yet, so pin it and expect small changes.
Import it from the mobile package (not @protocore/pds), inside a <PdsProvider> — there is no stylesheet, so style (a ViewStyle) replaces className and every value comes from the theme:
import { EmptyState } from "@protocore/pds-mobile";Parity with web. A centered "no data" panel inside a dashed hairline frame.
- Slots:
icon, a mono uppercaseeyebrow(defaultNO DATA),title,description, and anaction(e.g. a Button).
<EmptyState
eyebrow="NO DEPLOYS"
title="Nothing shipped yet"
description="Your deployments will show up here."
action={<Button>Deploy service</Button>}
/>EmptyState props
| Prop | Type | Default | Description |
|---|---|---|---|
action | ReactNode | — | Action slot (e.g. a Button) shown below the body. |
className | string | — | |
description | ReactNode | — | Secondary explanatory copy. |
eyebrow | ReactNode | NO DATA | Mono uppercase eyebrow above the title. |
icon | ReactNode | — | Optional decorative icon slot, rendered above the eyebrow. |
style | CSSProperties | — | |
title | ReactNode | — | Sentence-case headline. |