---
source_url: https://www.pubnub.com/docs/chat/community-supported/android/ui-theming
title: UI theming for PubNub Chat Components for Android
updated_at: 2026-06-17T11:36:43.193Z
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# UI theming for PubNub Chat Components for Android

PubNub Chat Components for Android rely on the [Material Theme](https://developer.android.com/jetpack/compose/themes/material) from Jetpack Compose that defines default values for your application [color](https://material.io/design/color/the-color-system.html), [typography](https://material.io/design/typography/the-type-system.html), and [shape](https://material.io/design/shape/about-shape.html) attributes, allowing your app to have a consistent look and feel.

## App theme

Compose libraries are used across our components, their default themes, and renderers that define how the components are drawn on the screen. [Chat Provider](https://www.pubnub.com/docs/chat/community-supported/android/chat-provider) applies the default themes to all components that make references to them. This happens at the start of every app built with PubNub Chat Components for Android.

Our [Getting Started (GS) app](https://www.pubnub.com/docs/chat/community-supported/android) applies the default Material Theme in the `Theme.kt` file:

```kotlin
MaterialTheme(
    colors = colors,
    typography = Typography,
    shapes = Shapes,
) {

    ChatProvider(pubNub) {
        content()
    }
}
```

### Light and dark themes

Light and [dark](https://developer.android.com/jetpack/compose/themes/material#dark-theme) themes, same as in Jetpack Compose, are defined in components by providing different pairs of colors (primary, secondary, etc.) that are used respectively in light and dark themes of your app (the so-called `LightColorPalette` and `DarkColorPalette`).

This is how the GS app uses both palettes to define the app theme:

```kotlin
@Composable
fun AppTheme(
    pubNub: PubNub,
    database: DefaultDatabase = Database.initialize(LocalContext.current),
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable() () -> Unit,
) {
    val colors = if (darkTheme) DarkColorPalette
    else LightColorPalette
```

### Change light and dark palettes

To override these default color palettes in your app, simply provide different values for specific parameters in both light and dark color sets.

See overrides from the GS app in the `Theme.kt` file:

```kotlin
private val DarkColorPalette = darkColors(
    primary = Light4,
    primaryVariant = Amaranth,
    secondary = Light4,
    onPrimary = Amaranth,
)

private val LightColorPalette = lightColors(
    primary = Light4,
    primaryVariant = Amaranth,
    onPrimary = Amaranth,
    secondary = Light4,
    onSecondary = Amaranth,
    onSurface = DustyGray,
    onBackground = MineShaft,
```

:::tip Variables
Specific values for variables like `Light4` or `Amaranth` are defined in the `Color.kt` file in the GS app.
:::

You can use the [Material palette generator](https://material.io/design/color/the-color-system.html#tools-for-picking-colors) to help you choose the most appropriate light and dark sets of colors for your app.

### Change shapes and typography

Similarly to the colors, you can override the default values for shapes and typography provided by the Material Theme. Our GS app differentiates the following types of shapes in the `Shape.kt` file:

```kotlin
val Shapes = Shapes(
    small = RoundedCornerShape(4.dp),
    medium = RoundedCornerShape(4.dp),
    large = RoundedCornerShape(0.dp)
)
```

It also specifies the typography for long-form writing ([body1](https://material.io/develop/web/guides/typography)) used in the GS app (`Type.kt`):

```kotlin
val Typography = Typography(
    body1 = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Normal,
        fontSize = 16.sp
    )
)
```

## Component themes

With Material Theme supporting the implementation of PubNub Chat Components for Android implementation, we defined how each of our components should look and behave. For this purpose, we created separate themes for each component and default renderers that specify how these components behave in a final app.

All these component themes are separate Android classes and have a unified naming convention of `{ComponentName}Theme`, like `TypingIndicatorTheme`.

:::tip Default themes and renderers
You can see all default component themes in specific component folders in the [chat-components-android](https://github.com/pubnub/chat-components-android/blob/master/chat-components/ui/src/main/java/com/pubnub/components/chat/ui/component/channel/ChannelListTheme.kt) repository. Each component folder contains a theme file (like `TypingIndicatorTheme.kt`) and a renderer file under the `renderer` folder (like `TypingIndicatorRenderer.kt` with its default implementation specified in `DefaultTypingIndicatorRenderer.kt`).
:::

Each component theme has a specified list of parameters it takes. These parameters define what the component looks like and only these parameters can be customized.

Just like Chat Provider handles the default app theme, component themes are applied by [PubNub local theme providers](https://www.pubnub.com/docs/chat/community-supported/android/chat-provider#themes), such as `LocalTypingIndicatorTheme`.

Let's analyze how these default component themes are composed based on the `TypingIndicatorTheme` class.

```kotlin
class TypingIndicatorTheme(
    modifier: Modifier,
    icon: IconTheme,
    text: TextTheme,
)
```

As you can see, the `TypingIndicatorTheme` class takes the `modifier`, `icon`, and `text` parameters. Each of them has a hierarchical structure and references a variable that is specified in one common `ThemeDefaults` object in the [ThemeDefaults.kt](https://github.com/pubnub/chat-components-android/blob/master/chat-components/ui/src/main/java/com/pubnub/components/chat/ui/component/common/ThemeDefaults.kt) file in the repository.

See the `TypingIndicatorTheme` example and the composable function in which it is specified:

```kotlin
object ThemeDefaults {
...
    @Composable
    fun typingIndicator(
        modifier: Modifier = Modifier
            .fillMaxWidth()
            .padding(12.dp),
        icon: IconTheme = IconThemeDefaults.icon(
            tint = MaterialTheme.colors.primaryVariant.copy(
                alpha = ContentAlpha.medium
            )
        ),
        text: TextTheme = TextThemeDefaults.text(
            fontSize = 12.sp,
            color = MaterialTheme.colors.onSurface.copy(alpha = 0.54f)
        ),
    ) = TypingIndicatorTheme(modifier, icon, text)
}
```

The `typingIndicator` function takes:

* modifier which is a native Compose object that allows you to decorate your composable function and change its layout, behavior, and appearance by changing the given element's padding, width, or hight. Each theme for a given PubNub Chat Component for Android contains a modifier and allows you to customize the component to your needs. In this example, the typingIndicator function uses the Compose modifier to set the maximum width of the typing indicator and change the padding to 12 dp.
* icon references IconTheme and overrides the IconThemeDefaults theme for an icon. Apart from default themes for components, we also provide the default themes for common objects used across multiple components, such as buttons, icons, shapes, or texts. See all of them defined in the common folder. In this example, the typingIndicator function uses the IconThemeDefaults theme for the icon but overrides the importance hierarchy of the Material Theme primary color for the tint to medium using the ContentAlpha object from Jetpack Compose.
* text, similarly to icon, references and overrides our in-house default theme. In this example, it specifies that the typingIndicator must use TextThemeDefaults with fontSize of 12.sp and Material Theme onSurface color at 54% opacity.

:::tip PubNub themes
All in-house PubNub themes for components and common elements have a unified naming convention and end with the `Theme` suffix, like `TextTheme`.
:::

### Customize component theme

Now that you know how these component and element themes work in PubNub Chat Components for Android, see how you can override the default values they provide in your app.

Customization allows you to change such parameters as the position on the screen (through modifiers), colors, text sizes, and icons. To customize the look of a component, create a custom theme for the component in which you override one or a few default parameters specified for the component in the [ThemeDefaults.kt](https://github.com/pubnub/chat-components-android/blob/master/chat-components/ui/src/main/java/com/pubnub/components/chat/ui/component/common/ThemeDefaults.kt) file. You then need to pass the new custom theme to the `{ComponentName}Theme` function, for example `ChannelListTheme`, using the Android native helper called [CompositionLocalProvider](https://www.pubnub.com/docs/chat/community-supported/android/chat-provider). To propagate the new style onto all child elements, call a specific [PubNub local provider](https://www.pubnub.com/docs/chat/community-supported/android/chat-provider#themes) for the theme (in this example it would be `LocalChannelListTheme`).

You can do the same to override the default values for the default element themes and customize values for such elements as buttons, icons, or shapes. See the [common](https://github.com/pubnub/chat-components-android/tree/master/chat-components/ui/src/main/java/com/pubnub/components/chat/ui/component/common) folder for the list of all available themes.

### Change message list width

The `ThemeDefaults` object specifies that the message list is drawn at full width through the modifier value of `Modifier = Modifier.fillMaxWidth()`:

```kotlin
object ThemeDefaults {
...
    @Composable
    fun messageList(
        modifier: Modifier = Modifier.fillMaxWidth(),
        arrangement: Arrangement.Vertical = Arrangement.spacedBy(8.dp),
        message: MessageTheme = message(),
        messageOwn: MessageTheme = message(
            title = TextThemeDefaults.messageTitle(MaterialTheme.colors.primary),
            shape = ShapeThemeDefaults.messageBackground(
                color = MaterialTheme.colors.primary.copy(
                    alpha = 0.4f
                )
            )
        ),
        separator: TextTheme = TextThemeDefaults.messageSeparator(),
    ) = MessageListTheme(modifier, arrangement, message, messageOwn, separator)
}
```

To override the default maximum width of the message list in your app, create a custom theme in which you change the `modifier` value to `200.dp`:

```kotlin
val customTheme = ThemeDefaults.messageList(modifier = Modifier.width(200.dp))
MessageListTheme(customTheme) {
   MessageList(messages)
}
```

Pass the new value to the `MessageListTheme` composable function using the `CompositionLocalProvider` helper and the `LocalMessageListTheme` theme provider:

```kotlin
@Composable
fun MessageListTheme(
    theme: MessageListTheme,
    content: @Composable() () -> Unit,
) {
    CompositionLocalProvider(LocalMessageListTheme provides theme) {
        content()
    }
}
```

### Change input shape

The `InputThemeDefaults` object specifies that the shape of the input box (`shape`) uses the default medium shape provided by the Material Theme:

```kotlin
object InputThemeDefaults {
    @Composable
    fun input(
        shape: Shape = MaterialTheme.shapes.medium,
        colors: TextFieldColors = TextFieldDefaults.textFieldColors(
            textColor = MaterialTheme.colors.contentColorFor(MaterialTheme.colors.background),
        ),
    ) = InputTheme(shape, colors)
}
```

Override the shape of the input box to apply 50% to all four corners:

```kotlin
val customTheme = ThemeDefaults.input(shape = RoundedCornerShape(50))
MessageInputTheme(customTheme) {
   MessageInput()
}
```

Pass the new value to the helper:

```kotlin
@Composable
fun MessageInputTheme(
    theme: MessageInputTheme,
    content: @Composable() () -> Unit,
) {
    CompositionLocalProvider(LocalMessageInputTheme provides theme) {
        content()
    }
}
```

### Change message title color

The `ThemeDefaults` object specifies that the title of your own message (`messageOwn`) sent in a channel should use the default color provided by the Material Theme:

```kotlin
object ThemeDefaults {
...
    @Composable
    fun messageList(
        modifier: Modifier = Modifier.fillMaxWidth(),
        arrangement: Arrangement.Vertical = Arrangement.spacedBy(8.dp),
        message: MessageTheme = message(),
        messageOwn: MessageTheme = message(
            title = TextThemeDefaults.messageTitle(MaterialTheme.colors.primary),
            shape = ShapeThemeDefaults.messageBackground(
                color = MaterialTheme.colors.primary.copy(
                    alpha = 0.4f
                )
            )
        ),
        separator: TextTheme = TextThemeDefaults.messageSeparator(),
    ) = MessageListTheme(modifier, arrangement, message, messageOwn, separator)
```

Change the default title color to red:

```kotlin
val customTheme = ThemeDefaults.messageList(messageOwn = message(title = messageTitle(Color.Red))
)
MessageListTheme(customTheme) {
   MessageList(messages)
}
```

Pass the new value to the helper:

```kotlin
@Composable
fun MessageListTheme(
    theme: MessageListTheme,
    content: @Composable() () -> Unit,
) {
    CompositionLocalProvider(LocalMessageListTheme provides theme) {
        content()
    }
}
```

## Custom renderers

Each component has a default renderer that specifies how the component should behave and be drawn in an app built with PubNub Chat Components for Android. All component renderers, together with their default implementations, are defined in a given [component folder](https://github.com/pubnub/chat-components-android/tree/master/chat-components/ui/src/main/java/com/pubnub/components/chat/ui/component) under the `renderer` subfolder.

* ChannelList The default implementation of ChannelRenderer is available in the DefaultChannelRenderer.kt file. You can implement the following functions: FunctionDefault valueDescriptionChannel(name: String, description: String?, modifier: Modifier, profileUrl: String?, onClick: (() -> Unit)?, onLeave: (() -> Unit)?n/aA composable function to draw a channel item.Placeholder()n/aA composable placeholder used during data loading.Separator(title: String?, onClick: (() -> Unit)?)n/aA composable function to draw a separator for channel types.
* MemberList The default implementation of MemberRenderer is available in the DefaultMemberRenderer.kt file. You can implement the following functions: FunctionDefault valueDescriptionMember(name: String, description: String?, profileUrl: String, online: Boolean?, onClick: () -> Unit, modifier: Modifier)n/aA composable function to draw a member item.Separator(title: String)n/aA composable function to draw a separator for members.Placeholder()n/aA composable placeholder used during data loading.
* MessageList The default implementation of MessageRenderer is available in the GroupMessageRenderer.kt file. You can implement the following functions: FunctionDefault valueDescriptionMessage(messageId: MessageId, currentUserId: UserId, userId: UserId, profileUrl: String, online: Boolean?, title: String, message: AnnotatedString?, timetoken: Timetoken, reactions: List<ReactionUi>, onMessageSelected: (() -> Unit)?, onReactionSelected: ((Reaction) -> Unit)?, reactionsPickerRenderer: ReactionsRenderern/aA composable function to draw a message item.Placeholder()n/aA composable placeholder used during data loading.Separator(text: String)n/aA composable function to draw a separator for members.
* Message reactions (part of MessageList) The default implementation of ReactionsRenderer is available in the DefaultReactionsPickerRenderer.kt file. You can implement the following functions: FunctionDefault valueDescriptionfun Picker(onSelected: (Reaction) -> Unit)n/aComposable function to draw a reactions picker.fun PickedList(currentUserId: UserId, reactions: List<ReactionUi>, onSelected: (Reaction) -> Unit)n/aComposable function to draw all the reactions under the message.
* MessageInput The default implementation of TypingIndicatorRenderer is available in the DefaultTypingIndicatorRenderer.kt file. You can implement the following functions: FunctionDefault valueDescriptionTypingIndicator(data: List<TypingUi>)n/aA composable function to draw the typing indicator. The TypingUi data contains information about the user, typing state, and the last signal timestamp. 1data class TypingUi(2 val user: MemberUi.Data,3 val isTyping: Boolean,4 val timestamp: Long = System.currentTimeMillis().timetoken,5)

### Create a custom renderer

If you need to change the structure of the view, you can create a custom renderer that extends the corresponding component's interface and pass it using the `{componentName}Renderer` parameter. Each component has different customization options. Check the renderer interfaces and default implementations to see the available data and functions you can customize to your app needs.

For example, if you want to create a custom renderer for `TypingIndicator` that is a part of the `MessageInput` component, create a separate file, like `MyCustomTypingIndicatorRenderer.kt`, with a new configuration for a custom `MyCustomTypingIndicatorRenderer` and pass it through the `typingIndicatorContent` parameter when invoking the `MessageInput` component in your chat app:

```kotlin
MessageInput(
   …
   typingIndicatorContent = { typing ->
        MyCustomTypingIndicatorRenderer.TypingIndicator(typing)
    },
   …
)
```

## Other customization options

If you use PubNub Chat Components to add chat functionality to your existing application, you would need to create the chat view in your app and customize its look to your needs. To add additional files, like images or icons, and static content to your Android project, import them in Android Studio to the respective subfolder of the [res](https://developer.android.com/guide/topics/resources/providing-resources) directory. This way all referenced resources will be kept externally and only referenced in your app code when needed.

### Add chat string reference

For example, you can add a common `Chat` string value to the [values/strings.xml](https://developer.android.com/guide/topics/resources/string-resource) file and reference it in your app when adding a new view for your chat app:

```xml
<resources>
<string name="chat">Chat</string>
</resources>
```

### Add chat icon image

You can also add a chat icon to be displayed in the app's bottom navigation menu. To do that, select an SVG image and import it into your Android Studio project as a [drawable resource](https://developer.android.com/guide/topics/resources/drawable-resource). Android Studio will convert it into an XML file. Read the official [Android documentation](https://developer.android.com/studio/write/image-asset-studio) to learn how to do that.