CalmUI
Components

Show Loading, Empty and Error States

Use GameUI feedback components while the owner loads data or handles a retry.

In a project containing the updated GameUI sources, open Components → Feedback in Studio. Preview LoadingState, EmptyState, or ErrorState. Each works with default text and the shared GameUI theme. These are source components, not new Blueprint nodes or a data-loading service.

Use the state that describes the real result:

  • LoadingState: a request is still running.
  • EmptyState: the request succeeded but returned no elements.
  • ErrorState: the request failed. Offer retry only when retry is possible.
  • Replace the state component with your normal content when data is available.

All three accept elementId, title, description, and a default slot for extra details. Give each instance a unique elementId. Titles and descriptions wrap; height follows content rather than a fixed card height. The components can sit inside a panel or fill a view's content column.

LoadingState

Without progress, an animated spinner indicates an unknown duration. It does not invent a percentage or finish after a timer. With finite numeric progress, it uses the shared ProgressBar. max defaults to 100, values are clamped, and zero is a valid known progress value. Invalid/non-positive maxima produce an empty range. valueText optionally supplies a formatted value label.

For a standalone preview, put this source in a View at the GameUI root:

LoadingExample.calmui
<import component="LoadingState" from="./components/feedback/LoadingState.calmui" />
<template>
  <LoadingState elementId="save-loading"
                title="$loc('GameUI::Example.LoadingSave', 'Wczytywanie zapisu')"
                :progress="50" :max="100" />
</template>

Replace the numeric example with values supplied by your owner when loading real data. Do not advance a fake percentage just to keep the component moving.

Set cancellable to true to show Cancel. cancelLabel replaces its default text. The button emits cancel; it does not abort gameplay work or remove itself. After receiving the request, the owner can set cancelPending to disable further clicks while cancellation completes. disabled also disables the button.

The spinner uses ordinary CSS keyframes. Studio Play animates it without input; Pause and Fixed time intentionally stop animation playback.

EmptyState

The default title is “Brak elementów”. Supply a specific translated title, such as “Brak zapisów”, and a short explanation when useful. icon accepts a Lucide icon name and defaults to inbox.

An action appears only when actionLabel is non-empty. It emits action and supports mouse, keyboard and controller activation. disabled disables that button. The owner decides whether the action creates an item, clears a filter, opens another View, or does something else.

ErrorState

The default title reports that data could not be loaded. Supply a user-facing description; do not expose raw connection details, credentials or stack traces.

Retry is shown by default. Set retryable to false for errors that cannot be retried. The button emits retry. Set retrying immediately while handling that request: it disables the button, marks the component busy, and shows the pending label. Reset retrying after a rejected attempt, or replace the component when loading succeeds. disabled also disables Retry.

Use retryLabel and retryingLabel for custom wording. Retrying never changes data, clears the error, or switches screens by itself.

Connect the owner and localize text

Handle component events in the parent using the component event workflow. Forward real operations through your game action contract, and display the authoritative Store state returned by C++ or Blueprint. These components have no network client, save-system knowledge, or independent request queue.

Default labels use literal $loc keys under GameUI::Loading.*, GameUI::Empty.* and GameUI::Error.*. Pass translated custom text as props. See Translate Your UI. Localization and controller glyph assets remain project-owned.

If a spinner does not move, check Studio playback. If an action does nothing, check the parent's event handler and game action result. A visible button does not mean its operation has been wired to gameplay.

On this page