StateMessage
A centered state message for empty, not-found, loading, and success scenarios. Includes preset icons and a call-to-action button.
Overview
StateMessage displays a centered empty-state pattern with a decorative icon, title, description, and an optional button. It ships with six semantic presets (empty, notFound, success, error, warning, connectionError) that set the default icon and color, plus an isLoading flag that swaps the icon for a spinner. Every part is overridable via slots and slotProps.
Use it inside panels, modals, pages, or any area that needs to communicate status to the user.
Import
import { StateMessage } from '@unflow.io/ui/components/StateMessage';Props
| Prop | Type | Default | Description |
|---|---|---|---|
type | 'empty' | 'notFound' | 'success' | 'error' | 'warning' | 'connectionError' | 'empty' | Semantic preset that selects the default icon |
title | string | — | Primary heading |
description | string | — | Secondary body text |
cta | StateMessageCTA | — | Call-to-action button configuration. Preset defaults: secondary for most states, destructiveSecondary for error. All Button props can still be overridden. |
isLoading | boolean | false | Swaps the preset icon for a spinner |
disableRings | boolean | false | Hides the decorative rings behind the icon |
StateMessageCTA is the same shape as IButton:
export type StateMessageCTA = IButton;Presets
Empty
Empty message title text here
This is a subtitle text for the empty message. Keep it simple, but show the user what it needs to see some content here.
<StateMessage
type="empty"
title="Empty message title text here"
description="This is a subtitle text for the empty message."
cta={{ label: 'Button label', size: 'sm' }}
/>Not found
Not found message title text here
This is a subtitle text for the not found message. Keep it simple, but show the user what it needs to see some content here.
<StateMessage
type="notFound"
title="Not found message title text here"
description="This is a subtitle text for the not found message."
cta={{ label: 'Button label', size: 'sm' }}
/>Loading
Loading message title text here
This is a subtitle text for the loading message. Keep it simple, but show the user what it needs to see some content here.
<StateMessage
type="empty"
isLoading
title="Loading message title text here"
description="This is a subtitle text for the loading message."
/>Success
Success message title text here
This is a subtitle text for the success message. Keep it simple, but show the user what it needs to see some content here.
<StateMessage
type="success"
title="Success message title text here"
description="This is a subtitle text for the success message."
cta={{ label: 'Button label', size: 'sm' }}
/>Error
Error message title text here
This is a subtitle text for the error message. Keep it simple, but show the user what it needs to see some content here.
<StateMessage
type="error"
title="Error message title text here"
description="This is a subtitle text for the error message."
cta={{ label: 'Button label', size: 'sm' }}
/>Warning
Warning message title text here
This is a subtitle text for the warning message. Keep it simple, but show the user what it needs to see some content here.
<StateMessage
type="warning"
title="Warning message title text here"
description="This is a subtitle text for the warning message."
cta={{ label: 'Button label', size: 'sm' }}
/>Connection error
Connection error message title text here
This is a subtitle text for the connection error message. Keep it simple, but show the user what it needs to see some content here.
<StateMessage
type="connectionError"
title="Connection error message title text here"
description="This is a subtitle text for the connection error message."
cta={{ label: 'Button label', size: 'sm' }}
/>Full-width button
Set cta.fullWidth when the message lives in a narrow container, such as a drawer or a card.
Empty message title text here
Use cta.fullWidth when the state message sits inside a narrow container.
<StateMessage
type="empty"
title="Empty message title text here"
description="Use cta.fullWidth when the state message sits inside a narrow container."
cta={{ label: 'Button label', size: 'sm', fullWidth: true }}
/>Customization (slots)
Replace the preset icon with any React node:
Custom icon
You can override the preset icon with any React node using slots.icon.
import { Cloud } from '@unflow-ui/icons/system-devices/cloud';
<StateMessage
type="empty"
title="Custom icon"
description="You can override the preset icon with any React node using slots.icon."
slots={{ icon: <Cloud /> }}
/>Customization (slotProps)
| Slot | Props | Description |
|---|---|---|
icon | BaseHTMLProps<HTMLDivElement> | Icon wrapper, including the decorative rings |
loadingIcon | BaseHTMLProps<HTMLDivElement> & Pick<ISpinner, 'size' | 'thickness'> | Loading indicator wrapper and spinner sizing props |
title | BaseHTMLProps<HTMLHeadingElement> | Heading element |
description | BaseHTMLProps<HTMLParagraphElement> | Body text element |
cta | IButton | CTA button props |
Accessibility
- The root is a
<div>with centered text. Use inside a region or landmark when it is the main content of a page. - Preset icons are decorative and not focusable.
- The loading state uses the existing
Spinnercomponent, which rendersrole="status". Override it viaslots.loadingIconor tweak its size/thickness throughslotProps.loadingIcon. - Provide meaningful
titleanddescriptiontext so the message is understandable without the icon. - When
ctais supplied, the button is a standardButtonand inherits its keyboard and focus behavior.