This is beta documentation for Stream Chat Android SDK v7. For the latest stable version, see the latest version (v6) .

Custom Composer

The MessageComposer component can be customized at two levels:

  1. Parameters: Adjust the existing UI using MessageComposer parameters like modifier, input, and onAttachmentsClick.
  2. Component Factory: Replace the leading/trailing content, input field, or attachment picker UI by overriding methods in ChatComponentFactory.

For most customizations, the Component Factory approach is recommended. See the Component Factory page for details on overriding MessageComposerLeadingContent(), MessageComposerTrailingContent(), and other composer slots.

Parameter-Level Customization

If you need to customize the composer within a custom screen (without using MessagesScreen), create it directly with MessageComposerViewModel:

@Composable
private fun CustomMessageComposer(
    composerViewModel: MessageComposerViewModel,
    attachmentsPickerViewModel: AttachmentsPickerViewModel,
) {
    MessageComposer(
        viewModel = composerViewModel,
        modifier = Modifier
            .fillMaxWidth()
            .wrapContentHeight(),
        input = { composerState ->
            MessageInput(
                messageComposerState = composerState,
                onValueChange = { composerViewModel.setMessageInput(it) },
                onAttachmentRemoved = { composerViewModel.removeAttachment(it) },
                modifier = Modifier
                    .padding(horizontal = 10.dp)
                    .align(Alignment.CenterVertically),
            )
        },
        onAttachmentsClick = { attachmentsPickerViewModel.setPickerVisible(true) },
    )
}

The input parameter gives you access to MessageComposerState, which contains the current message text, attachments, and other state. You can use the built-in MessageInput component with custom modifiers, or replace it entirely with your own composable.

Integrating in a Custom Screen

When building a custom messages screen, wire the composer alongside the message list and attachment picker:

@Composable
fun CustomScreen(cid: String, onBackClick: () -> Unit = {}) {
    val viewModelFactory = MessagesViewModelFactory(LocalContext.current, channelId = cid)
    val listViewModel = viewModel(modelClass = MessageListViewModel::class.java, factory = viewModelFactory)
    val composerViewModel = viewModel(modelClass = MessageComposerViewModel::class.java, factory = viewModelFactory)
    val attachmentsPickerViewModel = viewModel(modelClass = AttachmentsPickerViewModel::class.java, factory = viewModelFactory)

    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) {
        Scaffold(
            topBar = { /* MessageListHeader */ },
            bottomBar = {
                CustomMessageComposer(
                    composerViewModel = composerViewModel,
                    attachmentsPickerViewModel = attachmentsPickerViewModel,
                )
            },
            content = { /* MessageList */ },
        )

        if (attachmentsPickerViewModel.isPickerVisible) {
            AttachmentPicker(attachmentsPickerViewModel = attachmentsPickerViewModel)
        }
    }
}