# Message Center message view

Show a single Message Center message with MessageCenterMessageView, add a navigation bar, customize the message view style, or render only the message body.

The message view shows a single Message Center message. Use it alongside your own [list view](https://www.airship.com/docs/developer/sdk-integration/apple/message-center/custom/list-view/), or to deep link directly to a message.

- `MessageCenterMessageView` shows the message with no navigation bar.
- `MessageCenterMessageViewWithNavigation` adds a navigation bar with a title and delete button.
- `MessageCenterMessageContentView` renders only the message body, so you provide all surrounding UI.

## MessageCenterMessageView

Show a message by its ID. Provide a `dismissAction` to handle closing the view.


#### Swift


```swift
import SwiftUI
import AirshipMessageCenter

struct MyMessageScreen: View {
    let messageID: String

    var body: some View {
        MessageCenterMessageView(messageID: messageID) {
            // Handle dismiss
        }
    }
}
```




## MessageCenterMessageViewWithNavigation

`MessageCenterMessageViewWithNavigation` wraps the message in a navigation bar with a title and a delete button. It's the destination used by [MessageCenterContent](https://www.airship.com/docs/developer/sdk-integration/apple/message-center/custom/inbox-view/#messagecentercontent) when a message is selected.

```swift
public init(
    messageID: String,
    title: String? = nil,
    showBackButton: Bool? = nil,
    dismissAction: (@MainActor () -> Void)? = nil
)
```


- `title`: The title shown until the message loads. The final title comes from the message.
- `showBackButton`: Whether to show a back button. When unset, the back button appears only when the view is presented modally.
- `dismissAction`: Called when the view is dismissed.

The delete button is hidden when `hideDeleteButton` is set in the [theme](https://www.airship.com/docs/developer/sdk-integration/apple/message-center/getting-started/#applying-a-custom-theme).

## Custom message view style {#custom-message-view-style}

To customize the message presentation, implement `MessageViewStyle` and return your own view from `makeBody(configuration:)`. The configuration provides the message view model and the dismiss action.


#### Swift


```swift
struct CustomMessageViewStyle: MessageViewStyle {
    func makeBody(configuration: Configuration) -> some View {
        NavigationStack {
            MessageCenterMessageView(
                viewModel: configuration.viewModel,
                dismissAction: configuration.dismissAction
            )
            .navigationTitle("Message")
        }
    }
}
```




Apply the style with the `.messageCenterMessageViewStyle(_:)` modifier:

```swift
MessageCenterView()
    .messageCenterMessageViewStyle(CustomMessageViewStyle())
```


## MessageCenterMessageContentView

`MessageCenterMessageContentView` renders only the message body (either a web body or a native ([Scene](https://www.airship.com/docs/reference/glossary/#scene)) layout). It has no loading indicator, error UI, retry, or mark-as-read behavior. Instead, it reports its state through a `phase` binding so you can provide your own chrome. Use it when you need complete control over everything around the message content.

```swift
public init(
    viewModel: MessageCenterMessageViewModel,
    phase: Binding<MessageCenterMessageContentPhase>,
    dismissAction: (@MainActor @Sendable () -> Void)? = nil
)
```


Set the phase to `.loading` to load the content. The view updates the binding to `.loaded` or `.error(_:)` as it loads:


#### Swift


```swift
import SwiftUI
import AirshipMessageCenter

struct MyMessageContentScreen: View {
    @StateObject
    private var viewModel: MessageCenterMessageViewModel

    @State
    private var phase: MessageCenterMessageContentPhase = .loading

    init(messageID: String) {
        _viewModel = .init(wrappedValue: MessageCenterMessageViewModel(messageID: messageID))
    }

    var body: some View {
        ZStack {
            MessageCenterMessageContentView(viewModel: viewModel, phase: $phase)

            switch phase {
            case .loading:
                ProgressView()
            case .error:
                Text("Unable to load message")
            case .loaded:
                EmptyView()
            }
        }
    }
}
```



