# Accessible List Labels

> **Info:** This is documentation for **Stream Chat React SDK v14**, which is no longer actively maintained. For up-to-date documentation, see the [latest version (v15)](https://getstream.io/chat/docs/sdk/react/).

Every channel and thread list row exposes a single, composed accessible name so a screen reader announces one coherent sentence per row instead of walking each nested element. This recipe shows how to reshape that name: adding your own segments, reordering them, and taking full control.

For the underlying model and API surface see the [Accessibility guide](https://getstream.io/chat/docs/sdk/react/v14/guides/accessibility/#customizing-accessible-names-for-list-rows).

## How the label is built

The name is assembled from named **parts**, joined by a separator, in a defined **order**. `ChannelListItemUI` and `ThreadListItemUI` accept an `accessibleLabelConfig` prop that lets you override any of this:

- `parts` is merged over the defaults, so a new key is _added_ and a same-named key _overrides_.
- `order` decides which parts render and in what sequence. A part not listed in `order` is never rendered, even if defined.
- `separator` joins non-empty parts (defaults to `'. '`).
- `build` bypasses everything and returns the whole string yourself.

The default channel row reading order is name, active, unread count, last message, attachments, link preview, delivery status, time. The default thread row order is channel name, active, unread count, parent message, reply count, last activity.

## Adding custom parts to a channel row

Supply your own `ChannelListItemUI` through [`ComponentContext`](https://getstream.io/chat/docs/sdk/react/v14/components/contexts/component-context/) and forward an `accessibleLabelConfig`. Below we announce `Pinned`, `Muted`, and `Frozen` state right after the channel name. Each part returns its segment string, or `undefined` to be omitted, so `Pinned` is only spoken when the channel is actually pinned.

```tsx
import {
  Channel,
  ChannelList,
  ChannelListItemUI as DefaultChannelListItemUI,
  Chat,
  DEFAULT_CHANNEL_LIST_ITEM_LABEL_ORDER,
  WithComponents,
  type ChannelListItemLabelConfig,
  type ChannelListItemUIProps,
} from "stream-chat-react";

const accessibleLabelConfig: ChannelListItemLabelConfig = {
  parts: {
    pinned: ({ channel, t }) =>
      channel.state.membership?.pinned_at ? t("Pinned") : undefined,
    muted: ({ channel, t }) =>
      channel.muteStatus().muted ? t("Muted") : undefined,
    frozen: ({ channel, t }) =>
      channel.data?.frozen ? t("Frozen") : undefined,
  },
  // Spread the defaults so you keep the built-in segments, then insert your own after `name`.
  order: [
    "name",
    "pinned",
    "muted",
    "frozen",
    ...DEFAULT_CHANNEL_LIST_ITEM_LABEL_ORDER.slice(1),
  ],
};

const CustomChannelListItem = (props: ChannelListItemUIProps) => (
  <DefaultChannelListItemUI
    {...props}
    accessibleLabelConfig={accessibleLabelConfig}
  />
);

export const App = ({ client }) => (
  <Chat client={client}>
    <WithComponents overrides={{ ChannelListItemUI: CustomChannelListItem }}>
      <ChannelList
        filters={{ type: "messaging", members: { $in: [client.userID] } }}
      />
    </WithComponents>
    <Channel>{/* ... */}</Channel>
  </Chat>
);
```

A pinned, muted channel now reads roughly:

> General. Pinned. Muted. 3 unread messages. Last message from Alice: see you soon. 2 days ago

>
> **Note:** Parts call the translate function `t`, so provide your own i18n keys (or return plain strings). The SDK does not ship `Pinned`, `Muted`, or `Frozen` strings.
>

## Reordering or dropping default parts

Because `order` is the single source of truth for what renders, you can trim a verbose label by listing only the parts you want. This announces just the name, unread count, and last message, dropping attachments, link previews, delivery status, and time:

```tsx
const accessibleLabelConfig: ChannelListItemLabelConfig = {
  order: ["name", "unreadCount", "lastMessage"],
};
```

## Customizing thread rows

`ThreadListItemUI` works the same way with `ThreadListItemLabelConfig` and `DEFAULT_THREAD_LIST_ITEM_LABEL_ORDER`. Here we add the participant count after the channel name:

```tsx
import {
  ThreadListItemUI as DefaultThreadListItemUI,
  DEFAULT_THREAD_LIST_ITEM_LABEL_ORDER,
  type ThreadListItemLabelConfig,
  type ThreadListItemUIProps,
} from "stream-chat-react";

const accessibleLabelConfig: ThreadListItemLabelConfig = {
  parts: {
    participants: ({ participantCount, t }) =>
      participantCount
        ? t("{{ count }} participants", { count: participantCount })
        : undefined,
  },
  order: [
    "name",
    "participants",
    ...DEFAULT_THREAD_LIST_ITEM_LABEL_ORDER.slice(1),
  ],
};

const CustomThreadListItem = (props: ThreadListItemUIProps) => (
  <DefaultThreadListItemUI
    {...props}
    accessibleLabelConfig={accessibleLabelConfig}
  />
);
// Provide { ThreadListItemUI: CustomThreadListItem } through ComponentContext.
```

## Taking full control

When part composition is not enough, set `build` to return the entire string. It receives the same row data and ignores `order`, `parts`, and `separator`:

```tsx
const accessibleLabelConfig: ChannelListItemLabelConfig = {
  build: ({ channel, displayTitle, unreadCount, t }) => {
    const name = displayTitle ?? channel.data?.name ?? t("Unnamed channel");
    return unreadCount
      ? t("{{ name }}, {{ count }} unread", { count: unreadCount, name })
      : name;
  },
};
```

Alternatively, write a fully custom `ChannelListItemUI` and call `composeChannelListItemAccessibleLabel` directly, importing `defaultChannelListItemLabelParts` to reuse the built-in segments.

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/v14/guides/customization/accessibility/accessible-list-labels/](https://getstream.io/chat/docs/sdk/react/v14/guides/customization/accessibility/accessible-list-labels/).