StateView
StateView is a wrapper view that uses SummaryStackView to create an edge case look when the result of an operation needs to be presented.
Platform availability: iOS 17.0+
When to use:
- Use StateView when you need to display feedback for loading failures, empty states, or error conditions.
- Consider using ShimmerView when you want to show loading placeholders before content appears.
- Consider custom implementations for complex success screens that require navigation or multiple actions.
Import
import BackbaseDesignSystem
Visual reference
No results |
With Button |
With Two Buttons
|
Custom |
API reference
StateView
Properties
|
Property |
Type |
Description |
|---|---|---|
|
iconOrAnimationSize |
CGSize |
The iconOrAnimationSize specifies the size of the icon or animation view. Defaults to 144x144. |
|
padding |
UIEdgeInsets |
The padding specifies insets applied to the entire view. Defaults to .zero. |
|
titleLabelStyle |
Style<UILabel>? |
The titleLabelStyle applies a style closure to the title label. |
|
subtitleLabelStyle |
Style<UILabel>? |
The subtitleLabelStyle applies a style closure to the subtitle label. |
|
firstButtonStyle |
Style<Button>? |
The firstButtonStyle applies a style closure to the first button. |
|
secondButtonStyle |
Style<Button>? |
The secondButtonStyle applies a style closure to the second button. |
|
thirdButtonStyle |
Style<Button>? |
The thirdButtonStyle applies a style closure to the third button. |
|
titleLabel |
UILabel? |
The titleLabel displays the state title (read-only). |
|
subtitleLabel |
UILabel? |
The subtitleLabel displays the state message (read-only). |
|
firstButton |
Button? |
The firstButton is the primary action button (read-only). |
|
secondButton |
Button? |
The secondButton is the secondary action button (read-only). |
|
thirdButton |
Button? |
The thirdButton is the tertiary action button (read-only). |
|
imageView |
UIImageView? |
The imageView displays the state icon (read-only). |
Initializers
- init(params:)
- Initializes a StateView with the given parameters.
|
Parameter |
Type |
Description |
|---|---|---|
|
params |
StateViewInitParams |
Parameters to use for initialization |
StateViewConfiguration
A protocol for configuring a StateView.
|
Property |
Type |
Description |
|---|---|---|
|
iconName |
String? |
The iconName specifies the icon asset name representing the state. |
|
animationView |
UIView? |
The animationView displays an animation instead of an icon. |
|
title |
String |
The title specifies the state title text. |
|
subtitle |
String |
The subtitle specifies the state message text. |
|
firstButtonConfiguration |
ButtonConfiguration? |
The firstButtonConfiguration configures the primary action button. |
|
secondButtonConfiguration |
ButtonConfiguration? |
The secondButtonConfiguration configures the secondary action button. |
|
thirdButtonConfiguration |
ButtonConfiguration? |
The thirdButtonConfiguration configures the tertiary action button. |
ButtonConfiguration
|
Property |
Type |
Description |
|---|---|---|
|
title |
String |
The title specifies the button text. |
|
horizontalSpacers |
HorizontalSpacers? |
The horizontalSpacers specifies spacing for full-width button layout. |
|
action |
() -> Void |
The action closure is called when the button is tapped. |
Usage
Using predefined configurations
Three out-of-the-box state configurations are available:
let buttonConfiguration = ButtonConfiguration(title: "Custom Btn Title",
action: { /* do something when button clicked */ })
let configuration = LoadingFailureStateViewConfiguration(buttonConfiguration: buttonConfiguration)
let params = StateViewInitParams(configuration: configuration,
style: DesignSystem.shared.styles.stateView,
bundles: .main,
titleLabelMaxWidth: 150,
subtitleLabelMaxWidth: 300)
let stateView = StateView(params: params)
Full-width buttons
For full-width buttons, pass a value to horizontalSpacers:
// Use .zero when your state view blends in with your view's background
let buttonConfiguration = ButtonConfiguration(title: "Custom Btn Title",
horizontalSpacers: .zero,
action: { /* do something when button clicked */ })
// If your state view has its own background, pass non-zero spacers
let buttonConfiguration = ButtonConfiguration(title: "Custom Btn Title",
horizontalSpacers: HorizontalSpacers(value: DesignSystem.shared.spacer.md),
action: { /* do something when button clicked */ })
Generic state configuration
Use GenericStateViewConfiguration to construct a custom look:
let spacer = DesignSystem.shared.spacer.md
let style: Style<StateView> = DesignSystem.shared.styles.stateView <> { stateView in
stateView.titleLabelStyle = { label in
label.font = DesignSystem.shared.fonts.preferredFont(.body, .regular)
}
stateView.backgroundColor = UIColor(red: 101/255, green: 200/255, blue: 122/255, alpha: 1)
stateView.layer.cornerRadius = 8
stateView.clipsToBounds = true
stateView.padding = .init(top: spacer, left: 0, bottom: spacer, right: 0)
}
let configuration = GenericStateViewConfiguration(
iconName: nil,
title: "Custom Title",
subtitle: "This is a custom message",
animationView: animationView,
firstButtonConfiguration: ButtonConfiguration(title: "Click me", horizontalSpacers: .init(value: spacer), action: {
// First button action
}),
secondButtonConfiguration: ButtonConfiguration(title: "Another button", action: {
// Second button action
}))
let params = StateViewInitParams(configuration: configuration, style: style, bundles: .main)
let stateView = StateView(params: params)
Success screen
Create a success screen using the generic configuration:
let configuration = GenericStateViewConfiguration(
iconName: DesignSystem.Assets.icStateViewSuccess,
title: "Success",
subtitle: "This is a success message",
animationView: nil,
firstButtonConfiguration: ButtonConfiguration(title: "Click me", action: {
// First button action
}),
secondButtonConfiguration: ButtonConfiguration(title: "Another button", action: {
// Second button action
}))
let params = StateViewInitParams(configuration: configuration, bundles: .main)
let stateView = StateView(params: params)
Custom configuration
Create a struct conforming to StateViewConfiguration:
struct MyCustomStateViewConfiguration: StateViewConfiguration {
public let iconName: String?
public let title: String
public let subtitle: String
public let animationView: UIView?
public let firstButtonConfiguration: ButtonConfiguration?
public let secondButtonConfiguration: ButtonConfiguration?
public init(
iconName: String? = "some-icon-name",
title: String = "Some custom title",
subtitle: String = "Sorry something went wrong with this subtitle") {
self.iconName = iconName
self.animationView = nil
self.title = title
self.subtitle = subtitle
self.firstButtonConfiguration = nil
self.secondButtonConfiguration = nil
}
}
let params = StateViewInitParams(configuration: MyCustomStateViewConfiguration(),
bundles: .main)
let stateView = StateView(params: params)
Animation support
Use an animation view instead of a static icon:
// Using Lottie animation framework
let animationView = AnimationView(name: "success-animation")
animationView.contentMode = .scaleAspectFit
animationView.loopMode = .loop
animationView.animationSpeed = 0.8
let configuration = LoadingFailureStateViewConfiguration(animationView: animationView,
firstButtonAction: { /* do something when button clicked */ })
let params = StateViewInitParams(configuration: configuration, bundles: .main)
let stateView = StateView(params: params)
💡 NOTE: In a configuration, animationView has precedence over iconName. If both are set, the animation view is shown.
States and variants
The StateView component includes three predefined configurations:
|
Configuration |
Use case |
|---|---|
|
LoadingFailureStateViewConfiguration |
Loading failures and generic errors |
|
NoInternetConnectionStateViewConfiguration |
Network connectivity issues |
|
NoResultsStateViewConfiguration |
Empty search results or empty lists |
|
GenericStateViewConfiguration |
Custom states including success screens |
Customization
Styling
|
Style |
Description |
|---|---|
|
DesignSystem.shared.styles.stateView |
Default state view style |
Custom styles
Customize the default style:
DesignSystem.shared.styles.stateView = { stateView in
stateView.iconOrAnimationSize = CGSize(width: 200, height: 200)
stateView.padding = .init(top: 16, left: 0, bottom: 16, right: 0)
stateView.titleLabelStyle = { label in
label.font = DesignSystem.shared.fonts.preferredFont(.title1, .semibold)
label.textColor = UIColor.black
}
stateView.subtitleLabelStyle = { label in
label.font = DesignSystem.shared.fonts.preferredFont(.subheadline, .light)
label.textColor = UIColor.black
}
stateView.firstButtonStyle = DesignSystem.shared.styles.primaryButton
stateView.secondButtonStyle = DesignSystem.shared.styles.secondaryButton
}
Style configuration options
|
Property |
Description |
|---|---|
|
iconOrAnimationSize |
Size of the state view image or animation view |
|
padding |
Padding on the entire view |
|
titleLabelStyle |
Style for the title label (font, color) |
|
subtitleLabelStyle |
Style for the subtitle label (font, color) |
|
firstButtonStyle |
Button style for the first button |
|
secondButtonStyle |
Button style for the second button |
Accessibility
The StateView component is accessible by default with semantic elements that VoiceOver announces.
|
Element |
Accessibility behavior |
|---|---|
|
titleLabel |
Announced as static text |
|
subtitleLabel |
Announced as static text |
|
firstButton |
Announced as button with title |
|
secondButton |
Announced as button with title |
|
thirdButton |
Announced as button with title |
|
imageView |
Decorative, not announced by default |
Best practices:
- Set descriptive button titles for clear VoiceOver announcements
- The component adjusts font sizes for Dynamic Type automatically
Localization
Override the following strings to customize the text for the StateView on the app level:
"DesignSystem.stateView.noConnectionTitle" = "No internet connection";
"DesignSystem.stateView.noConnectionSubtitle" = "It seems that you're not online";
"DesignSystem.stateView.noConnectionButton" = "Try again";
"DesignSystem.stateView.noResultsTitle" = "No results to show";
"DesignSystem.stateView.noResultsSubtitle" = "We couldn't find anything to show here";
"DesignSystem.stateView.loadingFailureTitle" = "Couldn't load page";
"DesignSystem.stateView.loadingFailureSubtitle" = "Something went wrong";
"DesignSystem.stateView.loadingFailureButton" = "Try again";
💡 NOTE: Depending on how the StateView is implemented on a journey level, these strings may not have an effect. They only apply if the journey has left the text as default.
Dependencies
- External dependencies: None
- Internal dependencies:
- SummaryStackView: Used internally for layout
- Button: Used for action buttons
Design tokens
Component styling is applied automatically through the design system's theming infrastructure.
JSON tokens
This component uses semantic tokens only. See Semantic tokens below.
Semantic tokens
|
Token |
API Reference |
Description |
|---|---|---|
|
Colors |
Theme.colors.foreground.default |
Title text color |
|
Colors |
Theme.colors.foreground.subtle |
Subtitle text color |
|
Typography |
DesignSystem.shared.fonts.preferredFont(.title1, .semibold) |
Title font |
|
Typography |
DesignSystem.shared.fonts.preferredFont(.subheadline, .light) |
Subtitle font |
|
Spacing |
DesignSystem.shared.spacer.lg |
Layout spacing |
|
Spacing |
DesignSystem.shared.spacer.md |
Padding spacing |
|
Styles |
DesignSystem.shared.styles.stateView |
Default state view style |
|
Styles |
DesignSystem.shared.styles.primaryButton |
First button style |
|
Styles |
DesignSystem.shared.styles.secondaryButton |
Second button style |
See also
- SummaryStackView - The underlying layout component
- ShimmerView - For loading placeholder animations