EmptyState

EmptyState gives an otherwise blank view a clear purpose. Use it to explain what is absent, whether that result is expected, and what the user can do next. It is most useful for first-use, no-result, and cleared-content states where an empty surface would leave the user guessing.

Example

use fission::prelude::*;

let empty_projects: Widget = EmptyState {
    icon: Some(Icon::svg(material::file::create_new_folder::round()).into()),
    title: "No projects yet".into(),
    description: Some("Create a project to organise your team's work.".into()),
    action: Some(
        Button {
            variant: ButtonVariant::Primary,
            child: Some(Text::new("Create project").into()),
            on_press: Some(create_project),
            ..Default::default()
        }
        .into(),
    ),
}
.into();
Keep the action specific to the empty condition. A search with no matches might offer “Clear filters”; a first-use state might offer “Create project”. Omit the action when the message is sufficient.

Anatomy and layout

The widget has four regions:
1.
an optional icon or illustration;
2.
a required title;
3.
an optional description; and
4.
an optional action widget.
The icon, title, and description form one compact header group. The action sits in a separate region below it, so the message remains readable even when the action has a larger touch target.
EmptyState fills the available parent width while the message header is bounded to 384 layout points by the default recipe. The surface uses active spacing, minimum height, border, corner-radius, color, and typography tokens. A base surface recipe is composed with the theme's narrow surface override when the viewport is below its configured breakpoint. The built-in packages therefore use a 160-point minimum normally and a 128-point minimum below 640 points without requiring a second widget tree or an application-owned height. A directly supplied Icon receives the recipe's icon size and color when the icon has not set those values explicitly; illustrations and other retained widgets keep their own presentation. The title uses a medium weight; the description uses secondary text color and relaxed line height. Both are center-aligned.

Field reference

Field
Type
Meaning
Notes
icon
Option<Widget>
Optional visual that reinforces the state.
An unstyled Icon inherits the empty-state icon size and color; explicit icon styling and other retained widgets are preserved.
title
String
Concise explanation of what is absent.
Required. Make it understandable without the description.
description
Option<String>
Supporting context or guidance.
Omit it when the title and action already explain the state.
action
Option<Widget>
The smallest useful next action.
Usually a Button; the supplied widget owns its own semantics and interaction.

Semantics and interaction

EmptyState is presentational. It does not add a live-region role, move focus, or dispatch an action by itself. Text remains available in the normal semantic tree, while any supplied action retains its own button, link, or custom semantics. When the state replaces a previously focused result, manage focus in the surrounding screen according to that workflow instead of making every empty state announce or capture focus automatically.

Responsive, target, and motion behavior

The panel shrinks with a narrower parent because its width is 100%. The active design system owns the narrow breakpoint and only overrides fields it needs; all unspecified surface properties continue to come from the base recipe. The header and action recipes can bound their readable content independently. Its parent still needs to provide sensible horizontal room; test long translations, increased text scale, and compact screens so the action does not crowd the message. If several actions are genuinely required, compose a responsive action group as the action widget rather than widening the empty-state API.
The same presentation can lower to native, Web, Terminal, Static site, and SSR output. EmptyState registers no motion itself. Any motion composed around its content or action still follows the global Env::motion_preference, so the widget does not need its own preference branch. Controls supplied in action require an interactive target or browser island to dispatch reducers.

Production checklist

•
Distinguish an expected empty state from loading and error states.
•
Make the title state the condition, and use the description for useful context rather than filler.
•
Offer one clear recovery or creation action when one exists.
•
Verify the panel at the narrowest supported width and with long translated copy.
•
Preserve the supplied action's semantic name and keyboard behavior.
Previous
Divider
Next
Icon