# AttachmentsPicker

The `AttachmentsPicker` component allows users to pick media, file or media capture attachments to send to the chat. The picker is a **bound component** that loads all the data and prepares it for the user.

Internally, it sets up the following components:

- **Picker options**: The header in the picker that shows different types of attachment options people can choose from, media, files or media capture, as well as the **Confirm selection** button.
- **Image picker**: Shows a gallery of images to choose from the device.
- **File picker**: Shows a list of files to choose from the device. Also allows the user to open the file browser and pick more files from the system.
- **Media capture**: Shows the media capture option to the user and opens a media capture `Activity`.

The picker also handles required permissions for browsing files and capturing images.

Let's see how to use it.

## Usage

If you're using **screen** components, like the [`MessagesScreen`](https://getstream.io/chat/docs/sdk/android/v5/compose/message-components/messages-screen/), you don't have to do any setup for the `AttachmentsPicker`. If you're building custom screens, you can add the `AttachmentPicker` to the rest of your UI:

```kotlin
// The state if we need to show the picker or not
val isShowingAttachments = attachmentsPickerViewModel.isShowingAttachments

if (isShowingAttachments) {
    AttachmentsPicker( // Add the picker to your UI
        attachmentsPickerViewModel = attachmentsPickerViewModel,
        modifier = Modifier
            .align(Alignment.BottomCenter)
            .height(350.dp),
        onAttachmentsSelected = { attachments ->
            // Handle selected attachments
        },
        onDismiss = {
            // Handle dismiss
        }
    )
}
```

Because the `AttachmentsPicker` is a **bound** component, you should rely on the `AttachmentsPickerViewModel`'s state, to know if you should show the picker or not. To make sure the picker is shown only when it should be, wrap the component call in an `if` statement.

The code above will show the following UI:

![Default AttachmentsPicker component](https://getstream.io/docs-assets/images/22ab3fe9f7e3.png)

As you can see, the picker is really easy to add to the UI, and it lets your users choose from different types of attachments when sending their messages.

## Handling Actions

The `AttachmentsPicker` exposes these actions for customization, as per the signature:

```kotlin
@Composable
fun AttachmentsPicker(
    onAttachmentsSelected: (List<Attachment>) -> Unit,
    onDismiss: () -> Unit,
)
```

- `onAttachmentsSelected`: Handler when the user selects attachments and confirms the selection by clicking on the **Confirm selection** button.
- `onDismiss`: Handler when the picker is dismissed by clicking outside of the picker area or by pressing the system back button.

To customize the behavior of the picker, simply override these actions to fit your UI needs, like in the following example:

```kotlin
AttachmentsPicker(
    ..., // State and UI customization
    onAttachmentsSelected = { attachments ->
        // Dismiss the picker and store the attachments
        attachmentsPickerViewModel.changeAttachmentState(showAttachments = false)
        composerViewModel.addSelectedAttachments(attachments)
    },
    onDismiss = { // Reset the UI state and dismiss the picker
        attachmentsPickerViewModel.changeAttachmentState(showAttachments = false)
        attachmentsPickerViewModel.dismissAttachments()
    }
)
```

In the example above, when `onAttachmentsSelected()` is triggered, you call `onShowAttachments()` and dismiss the picker from the UI, but you also store the selected attachments in the `MessageComposerViewModel`, so that you can show them in the `MessageInput` component.

Alternatively, in `onDismiss()`, you hide the picker again and you call `attachmentsPickerViewModel.onDismiss()` to reset the picker state, such as the loaded files or images and the `AttachmentPickerMode`.

This is a very simple way to customize the behavior and connect the `AttachmentPicker` to the rest of your components.

## Customization

You can customize the `AttachmentsPicker` using the following parameters:

```kotlin
fun AttachmentsPicker(
    ..., // ViewModel and action handlers
    modifier: Modifier = Modifier,
    tabFactories: List<AttachmentsPickerTabFactory> = ChatTheme.attachmentsPickerTabFactories,
    shape: Shape = ChatTheme.shapes.bottomSheet,
)
```

- `modifier`: Allows you to customize the root content component of the picker and change its size, padding and more.
- `tabFactories`: Used to customize the tabs shown in the picker.
- `shape`: Allows you to override the `AttachmentsPicker` shape.

Here's an example of a full screen `AttachmentsPicker` dialog:

```kotlin
AttachmentsPicker(
    attachmentsPickerViewModel = attachmentsPickerViewModel,
    modifier = Modifier.fillMaxSize(), // Fill all the available space
    shape = RectangleShape, // Use a shape without rounded corners
    onAttachmentsSelected = { attachments ->
        // Handle selected attachments
    },
    onDismiss = {
        // Handle dismiss
    }
)
```

This snippet will provide the following UI:

![The AttachmentsPicker Component](https://getstream.io/docs-assets/images/f77b5055adae.png)

As you can see, the `AttachmentsPicker` component now occupies the whole screen.

Now let's see how to use the `tabFactories` parameter to replace the media capture tab in the picker with a custom one.

We'll need to create a custom `AttachmentsPickerTabFactory` for our custom tab and implement the methods to render the icon and the content of the tab:

```kotlin
class AttachmentsPickerCustomTabFactory: AttachmentsPickerTabFactory {

    override val attachmentsPickerMode: AttachmentsPickerMode
        get() = CustomPickerMode()

    @Composable
    override fun pickerTabIcon(isEnabled: Boolean, isSelected: Boolean) {
        Icon(
            painter = painterResource(id = R.drawable.ic_custom_tab),
            contentDescription = "Custom tab",
            tint = when {
                isSelected -> ChatTheme.colors.primaryAccent
                isEnabled -> ChatTheme.colors.textLowEmphasis
                else -> ChatTheme.colors.disabled
            },
        )
    }

    @Composable
    override fun pickerTabContent(
        attachments: List<AttachmentPickerItemState>,
        onAttachmentsChanged: (List<AttachmentPickerItemState>) -> Unit,
        onAttachmentItemSelected: (AttachmentPickerItemState) -> Unit,
        onAttachmentsSubmitted: (List<AttachmentMetaData>) -> Unit,
    ) {
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            Text(
                style = ChatTheme.typography.title3Bold,
                text = "Custom tab",
                color = ChatTheme.colors.textHighEmphasis,
            )
        }
    }
}
```

Next, we'll remove the factory for the media capture tab, add a factory for our custom tab and pass the resulting factory list to the picker:

```kotlin
val defaultTabFactories = AttachmentsPickerTabFactories.defaultFactories(mediaCaptureTabEnabled = false)
val customTabFactories = listOf(AttachmentsPickerCustomTabFactory())
val tabFactories = defaultTabFactories + customTabFactories

AttachmentsPicker(
    ...
    tabFactories = tabFactories
)
```

The code above will produce the following UI:

![The AttachmentsPicker Tabs](https://getstream.io/docs-assets/images/5fafbf626ab3.png)

As you can see, the media capture option is removed and the custom tab is visible on the screen, but it only shows a small text element. Our example is very simple, but you can create custom tabs that handle audio recordings, location sharing, calendar invites and much more.


---

This page was last updated at 2026-09-08T17:13:40.933Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/android/v5/compose/message-components/attachments-picker/](https://getstream.io/chat/docs/sdk/android/v5/compose/message-components/attachments-picker/).