# Customizing Components

The SwiftUI SDK components are fully customizable and interchangeable through the `ViewFactory` protocol that holds all the reusable views of the SDK. You can find the full reference of the `ViewFactory` protocol [here](https://github.com/GetStream/stream-chat-swiftui/blob/develop/Sources/StreamChatSwiftUI/ViewFactory.swift).

## View Factory

The `ViewFactory` protocol defines the swappable views of the chat experience. There are default implementations for all the views used in the SDK. If you want to customize a view, you will need to implement the `ViewFactory` protocol, but only implement the view you want to swap.

In most cases, your custom view only needs to conform to the standard SwiftUI `View` protocol and provide a `body` property, there's no need to implement additional lifecycle methods or protocols. The only exception is when customizing the navigation bar, where your custom view must conform to SwiftUI’s `ToolbarContent` protocol.

For example, if you want to change the default usar avatar view that is used in multiple views, you can implement the `makeMessageAvatarView()` slot in the `ViewFactory` protocol.

```swift
class CustomFactory: ViewFactory {

    @Injected(\.chatClient) public var chatClient

    private init() {}

    public static let shared = CustomFactory()

    func makeMessageAvatarView(for userDisplayInfo: UserDisplayInfo) -> some View {
        CustomMessageAvatarView(
            avatarURL: userDisplayInfo.imageURL,
            size: userDisplayInfo.size ?? .messageAvatarSize
        )
    }
}
```

Afterwards, you need to inject the `CustomFactory` in your view. To do this, you pass the newly created factory to the `ChatChannelListView`. If you are only using the `ChatChannelView`, you can pass the factory to it instead.

```swift
var body: some Scene {
    WindowGroup {
        ChatChannelListView(viewFactory: CustomFactory.shared)
    }
}
```

And that's everything needed to provide custom views for the SwiftUI SDK.

<admonition type="tip">

The `ViewFactory` protocol is generic over the views that it can replace, and there is no usage of `AnyView`. This allows SwiftUI to compute the diffing of the views faster and more accurately without any performance overhead.

</admonition>

## Additional ViewFactory slots (quick index)

If you want to swap less common parts of the UI, the SDK exposes additional `ViewFactory` hooks that are not covered in the main guides. Here is a quick index, grouped by area:

- **Channel list & navigation**
  - `makeChannelListContentModifier` (modify header + list + footer as one container)
  - `makeChannelBarsVisibilityViewModifier` (control top/bottom bars visibility)
  - `makeChannelLoadingView` (loading state for `ChatChannelView`)
- **Composer & pickers**
  - `makeComposerTextInputView` (custom text input)
  - `makeAttachmentTextView` (text preview for attachments)
  - `makeAssetsAccessPermissionView` (permission prompt UI)
  - `makePhotoAttachmentPickerView` (photo picker wrapper)
  - `makeCameraPickerView` (camera picker wrapper)
  - `makeFilePickerView` (file picker wrapper)
  - `makeAddUsersView` (add users flow)
- **Message list UI**
  - `makeMessageAuthorAndDateView` (author + date header layout)
  - `makeMessageDateView` (date label below/inside a message)
  - `makeLastInGroupHeaderView` (last-in-group header layout)
  - `makeMessageRepliesShownInChannelView` (inline “replies shown in channel” row)
  - `makeMessageListDateIndicator` / `makeDateIndicatorView` (date overlay/separator UI)
  - `makeScrollToBottomButton` / `makeJumpToUnreadButton` (list navigation helpers)
  - `makeSystemMessageView` / `makeDeletedMessageView` (system/deleted message UI)
  - `makeEditedMessageHeaderView` / `makeMessageTranslationFooterView` (edited/translation UI)
  - `makeMessageViewModifier` (apply a modifier to each message row)
  - `makeReactionsContentView` / `makeEmojiTextView` / `makeGiphyBadgeViewType` (reaction/emoji/Giphy visuals)
  - `makeBouncedMessageActionsModifier` (bounced message actions UI)
- **Gallery & media player**
  - `makeGalleryView` / `makeGalleryHeaderView` (media gallery UI)
  - `makeVideoPlayerView` / `makeVideoPlayerHeaderView` / `makeVideoPlayerFooterView` (video player UI)

If you need a specific hook, check the full `ViewFactory` reference linked above for parameters and default implementations.

## Accessing Dependencies

When building your own view components and you want to use the dependencies of the SwiftUI SDK, you can access them by using the `@Injected(\.keyPath)` property wrapper:

```swift
@Injected(\.chatClient) var chatClient
@Injected(\.colors) var colors
@Injected(\.fonts) var fonts
@Injected(\.images) var images
@Injected(\.utils) var utils
```

<admonition type="note">

The `@Injected` property wrapper works similarly to the `@Environment` in SwiftUI, but it also allows access to the dependencies in non-view related code. This approach is inspired by the following [Dependency Injection](https://www.avanderlee.com/swift/dependency-injection/) article by [Antoine van der Lee](https://www.avanderlee.com/).

</admonition>

### Extending with Custom Types

In some cases, you might also need to extend the `@Injected` property wrapper with your own types. For example, you may want to be able to access your custom types like this:

```swift
@Injected(\.customType) var customType
```

In order to achieve this, you first need to define your own `InjectionKey`, and define it's `currentValue`, which basically creates the new instance of your type.

```swift
class CustomType {
	// your custom logic here
}

struct CustomInjectionKey: InjectionKey {
    static var currentValue: CustomType = CustomType()
}
```

Next, you need to extend our `InjectedValues` with your own custom type, by defining its getter and setter.

```swift
extension InjectedValues {
    /// Provides access to the `CustomType` instance in the views and view models.
    var customType: CustomType {
        get {
            Self[CustomInjectionKey.self]
        }
        set {
            Self[CustomInjectionKey.self] = newValue
        }
    }
}
```

With these few simple steps, you can now access your custom type in both your app code and in your custom implementations of the views used throughout the SDK.

## Build Time Improvements

If you are customizing many view slots (over 15) from the SDK, and you have many generics in your codebase, it's a good idea to explicitly specify the types of your custom views with `typealias`. This will improve the build time of your project.

For example, in our `ViewFactory`, the `associatedType` for creating the no channels view is `NoChannels`:

```swift
associatedtype NoChannels: View
func makeNoChannelsView() -> NoChannels
```

In order to improve the build time, you would need to specify the associated type with a `typealias`, like this:

```swift
typealias NoChannels = CustomNoChannelsView
```

Then, your custom implementation of the factory method `makeNoChannelsView` will look like the following:

```swift
public func makeNoChannelsView() -> CustomNoChannelsView {
    CustomNoChannelsView()
}
```

You can find all the associated types we use in the `ViewFactory` [here](https://github.com/GetStream/stream-chat-swiftui/blob/main/Sources/StreamChatSwiftUI/ViewFactory.swift).


---

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

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