ComponentsFeedback

State Panel

One calm place for empty, loading, success, unavailable, and error states. It explains what happened and offers the next step.

No files yet

Upload the documents your work depends on, like price lists and contracts.

Usage

State panel usageTSX
import { StatePanel } from "@tulipfarm/sprout/state-panel";

<StatePanel
  kind="error"
  heading="h3"
  title="Could not open this file"
  description={error.message}
>
  <Button variant="outline" onClick={retry}>Try again</Button>
</StatePanel>

kind is "empty", "loading", "success", "unavailable", or "error". Loading shows a spinner, success a check, and error a warning. Empty and unavailable showicon, which defaults to an inbox. Any component that takes asize number works, including your own brand glyphs. Passicon= for a text-only empty or unavailable panel.

heading sets the title element, h1 to h4, and defaults to h2. Use h1 when the panel is the whole page, like a not-found route. An error panel must have children, so people always have a way to recover.

empty

No files yet

Upload the documents your work depends on, like price lists and contracts.

loading

Opening file

Preparing the document viewer.

success

Slack is connected

Agents can now post to the channels you choose.

unavailable

This format cannot be displayed

Download the original file to open it in a compatible application.

error

Sample preview

Empty state with a sampleTSX
<StatePanel
  kind="empty"
  icon={Files}
  title="No files yet"
  description="Upload the documents your work depends on."
  sample={<FilesPreview />}
>
  <Button><Add aria-hidden="true" />Upload files</Button>
</StatePanel>

Empty panels can take a sample: a picture of the page once it has content. The panel becomes a card that sizes to its container, not the window. The preview hides below 28rem and moves beside the text from 48rem. The preview is hidden from assistive technology and cannot be focused. Passundefined to fall back to the centered layout.

No files yet

Upload the documents your work depends on, like price lists, contracts, and policies. Files stay private until you share them.

Sample without actions

No models configured yet

Once your operator configures model providers, each model family appears here.

Optional sample

No workflows yet

Describe the steps once, then run them on a schedule.

Sample presets

Sixteen ready-made samples ship with State Panel, one for each TulipFarm page that can be empty. Each one is a State Sample window with fixed, realistic content.

Sample preset usageTSX
import { StatePanel, WorkflowsSample } from "@tulipfarm/sprout/state-panel";

<StatePanel
  kind="empty"
  icon={BranchDown}
  title={archived ? "No archived workflows" : "No workflows yet"}
  description="Describe the work in chat, review its diagram, then save and activate it."
  sample={archived ? undefined : <WorkflowsSample />}
>
  <Button variant="outline">New workflow</Button>
</StatePanel>

No files yet

Upload the documents your work depends on, like price lists, contracts, and policies. Files stay private until you share them.

<FilesSample /> · List · folder tiles and file-type icons · two-part trail · pages/files.tsx

Only RecordsSample takes data, because it copies the table you are looking at. Every preset also accepts the outer window props: label changes the “Example” chip, and className, data-*, and other div attributes go to the window root.

Every preset

Each card names the export and the TulipFarm page that shows it. Avatars, brand icons, file-type icons, and badges come from Sprõut's Avatar, Brand Icon, Attachment, and Badge.

Rows preset

Rows sample from a table definitionTSX
<RecordsSample
  table={table.definition.label}
  fields={table.definition.fields.map((field) => field.label)}
/>

table becomes the current crumb after “Tables”. The first threefields become columns. The first is wide and starts with a colored mark, and the rest share the space. With no fields, one wide “Row” column is shown. Cell values are gray bars, so the sample never shows made-up data.

Window props and overflow

Presets fill their container. Long titles, crumbs, and column names truncate with an ellipsis instead of widening the page.

Changing state

Render the panel that matches your request. Loading and success are announced politely; errors are announced right away. When a retry removes the focused button, move focus to the surrounding region.

Loading Google Drive

Checking your connection and files.

Actions

Children sit under the description. Use buttons, links rendered as buttons, guidance text, or an inline alert. Wrap several links in your own row to keep them side by side. A child that renders nothing leaves no gap.

Retry
Primary and link

Workspace access changed

Check your workspace access before continuing.

Back to overview
Action row

Inbox isn’t available yet

Tasks waiting for you are in Tasks, and your conversations are in Chats.

Guidance text

Ask again in the chat.

Inline alert

Slack isn’t connected

Connect Slack so agents can read and post in channels.

Slack status could not refresh.

Busy action

No default knowledge

Choose a shared drive that every new chat can read.

Back and retry

You can’t open this folder

Ask the owner to share it with you.

Back to My Drive
Success with action

Copied to your Drive

The copy is ready to edit in Google Sheets.

Loading with action

Waiting for Slack

Finish signing in on the Slack tab.

Conditional action

Channels are still syncing

Slack channels appear once the first sync finishes.

Requests, permissions, and routing in these examples are sample code. The package only draws the panel.

Accessibility

The icon tile is decorative. Error text uses role="alert"; loading and success text use role="status". Matchheading to the surrounding outline. Sample presets are pictures, not controls, and nothing in them can be focused. The panel fades in over 180ms and the spinner turns; reduced motion turns both off.