# Draft Messages

The SwiftUI SDK provides a way to create and manage draft messages.

Drafts are disabled by default. In order to enable this feature, you need to enable the `draftMessagesEnabled` flag when initializing `Utils`.

```swift
let utils = Utils(
    messageListConfig: MessageListConfig(draftMessagesEnabled: true)
)
let streamChat = StreamChat(chatClient: chatClient, utils: utils)
```

<admonition type="note">

Drafts on SwiftUI are available since version [4.75.0](https://github.com/GetStream/stream-chat-swift/releases/tag/4.75.0).

</admonition>

<admonition type="tip">

Draft messages are synchronized across devices and work seamlessly offline as well.

</admonition>

## Basic Usage

When draft messages are enabled, the logic of saving and deleting drafts will be handled automatically by the SDK. When a user starts typing a message and then navigates away from the conversation, the message content is automatically saved as a draft, for both Channels and Threads.

When the user returns to the conversation, the draft message will be loaded automatically into the composer. If the user clears the composer content or publishes the message, the draft will be deleted.

The draft messages user flow is described in the following diagram:

<mermaid>

```text
flowchart LR
    A[User Action]
    A -->|Leave Channel| F[Update Channel Draft]
    A -->|Leave Thread| E[Update Thread Draft]
    A -->|Clear Composer Content| D[Delete Draft]
    A -->|Publish Message| D[Delete Draft]
```

</mermaid>


## Customization

By default, the only additional UI added to the SDK when drafts are enabled is a preview of the draft message in the channel list and thread list. When a draft is saved, the draft message is shown in the channel list and thread list until the message is published or deleted.

The channel draft preview is displayed in the `ChatChannelListItem` when the`channel.draftMessage` exists, and the thread draft preview is displayed in the `ChatThreadListItem` when the `thread.parentMessage.draftReply` exists.

You can customize the drafts preview by swapping the `ChatChannelListItem` and `ChatThreadListItem` components through the `ViewFactory.makeChannelListItem()` and the `ViewFactory.makeThreadListItem()` methods, respectively.

## Draft List Query

At the moment, the SDK does not provide a default UI component to render the list of drafts from the current user. However, you can easily build your own component by using your `chatClient.currentUserController()` to fetch the drafts.

The current user controller has a `loadDraftMessages()` method that is responsible to query the drafts. It accepts a `query: DraftListQuery` parameter that allows you to customize the query.

The `DraftListQuery` has the following properties:

- `pagination`: The initial pagination information. By default is `Pagination(pageSize: 25, offset: 0)`
- `sorting`: The sorting criteria for the drafts. By default is `[.init(key: .createdAt, isAscending: false)]`

### Fetching Drafts

Below is an example on how to fetch the drafts with the default query:

```swift
// Load the draft messages for the current user
let currentUserController = chatClient.currentUserController()
currentUserController.loadDraftMessages { result in
    switch result {
    case .success(let drafts):
        print("Draft messages loaded: \(drafts)")
    case .failure(let error):
        print("Failed to load draft messages: \(error)")
    }
}
```

### Pagination

In case the `currentUserController.hasLoadedAllDrafts` is `false`, you can load the next page of drafts by calling `currentUserController.loadMoreDraftMessages()`. This method has an optional completion handler that will be called when the page finishes loading.

```swift
currentUserController.loadMoreDraftMessages { result in
    switch result {
    case .success(let drafts):
        print("Draft messages loaded: \(drafts)")
    case .failure(let error):
        print("Failed to load more draft messages: \(error)")
    }
}
```

### Delegate

Whenever the drafts are updated or deleted, the `CurrentChatUserControllerDelegate` will be notified in the following function:

```swift
func currentUserController(
    _ controller: CurrentChatUserController,
    didChangeDraftMessages draftMessages: [DraftMessage]
)
```


<admonition type="tip">

To see a full drafts list example implementation, you can check our Demo App example [here](https://github.com/GetStream/stream-chat-swift/blob/develop/DemoApp/Screens/DemoDraftMessageListVC.swift). It is in UIKit, but should give you an idea on how to implement the same logic in SwiftUI.

</admonition>

## Draft Events

By default, the SDK will react whenever a draft is updated or deleted. But, in case your app needs additional logic, these are the available draft events:

- `DraftUpdatedEvent`: Triggered when a draft is updated.
- `DraftDeletedEvent`: Triggered when a draft is deleted.



---

This page was last updated at 2026-04-17T17:33:37.560Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/ios/v4/swiftui/drafts/](https://getstream.io/chat/docs/sdk/ios/v4/swiftui/drafts/).