# Slidable Channel List Preview

Slidable Channel List Preview

### Introduction

The default slidable behavior within the channel list has been removed in v4 of the Stream Chat Flutter SDK.
This guide will show you how you can easily add this functionality yourself.

Please see our [full v4 migration guide](/chat/docs/sdk/flutter/v4/guides/migration_guide_4_0/) if you're migrating from an earlier version of the Stream Chat Flutter SDK.

![Slidable demo](@chat-sdk/flutter/v4/_assets/slidable_demo.jpg)

### Prerequisites

This guide assumes you are familiar with the Stream Chat SDK.
If you're new to Stream Chat Flutter, we recommend looking at our [getting started tutorial](https://getstream.io/chat/flutter/tutorial/).

**Dependencies:**

```dart
dependencies:
  flutter:
    sdk: flutter
  stream_chat_flutter: ^4.0.0
  flutter_slidable: ^1.2.0
```

⚠️ Note: The examples shown in this guide use the above packages and versions.

### Example Code - Custom Stream Channel Item Builder

In this example, you are doing a few important things in the ChannelListPage widget. You're:

- Using the **flutter_slidable** package to easily add slide functionality.
- Passing in the `itemBuilder` argument for the **StreamChannelListView** widget. This gives access to the current **BuildContext**, **Channel**, and **StreamChannelListTile**, and allows you to create, or customize, the stream channel list tiles.
- Returning a Slidable widget with two CustomSlidableAction widgets - to delete a channel and show more options. These widgets come from the flutter_slidable package.
- Adding `onPressed` behaviour to call `showConfirmationDialog` and `showChannelInfoModalBottomSheet`. These methods come from the **`stream_chat_flutter`** package. They have a few different on-tap callbacks you can supply, for example, `onViewInfoTap`. Alternatively, you can create custom dialog screens from scratch.
- Using the **StreamChannelListController** to perform actions, such as, `deleteChannel`.

```dart
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';

void main() async {
  final client = StreamChatClient(
    's2dxdhpxd94g',
  );

  await client.connectUser(
    User(id: 'super-band-9'),
    '''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''',
  );

  runApp(
    MyApp(
      client: client,
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({
    Key? key,
    required this.client,
  }) : super(key: key);

  final StreamChatClient client;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: (context, child) => StreamChat(
        client: client,
        child: child,
      ),
      home: ChannelListPage(
        client: client,
      ),
    );
  }
}

class ChannelListPage extends StatefulWidget {
  const ChannelListPage({
    Key? key,
    required this.client,
  }) : super(key: key);

  final StreamChatClient client;

  @override
  State<ChannelListPage> createState() => _ChannelListPageState();
}

class _ChannelListPageState extends State<ChannelListPage> {
  late final _controller = StreamChannelListController(
    client: widget.client,
    filter: Filter.in_(
      'members',
      [StreamChat.of(context).currentUser!.id],
    ),
    channelStateSort: const [SortOption('last_message_at')],
  );

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => Scaffold(
        body: SlidableAutoCloseBehavior(
          child: RefreshIndicator(
            onRefresh: _controller.refresh,
            child: StreamChannelListView(
              controller: _controller,
              itemBuilder: (context, channel, tile) {
                final chatTheme = StreamChatTheme.of(context);
                final backgroundColor = chatTheme.colorTheme.inputBg;
                final canDeleteChannel = channel.ownCapabilities
                    .contains(PermissionType.deleteChannel);
                return Slidable(
                  groupTag: 'channels-actions',
                  endActionPane: ActionPane(
                    extentRatio: canDeleteChannel ? 0.40 : 0.20,
                    motion: const BehindMotion(),
                    children: [
                      CustomSlidableAction(
                        onPressed: (_) {
                          showChannelInfoModalBottomSheet(
                            context: context,
                            channel: channel,
                            onViewInfoTap: () {
                              Navigator.pop(context);
                              // Navigate to info screen
                            },
                          );
                        },
                        backgroundColor: backgroundColor,
                        child: const Icon(Icons.more_horiz),
                      ),
                      if (canDeleteChannel)
                        CustomSlidableAction(
                          backgroundColor: backgroundColor,
                          child: StreamSvgIcon.delete(
                            color: chatTheme.colorTheme.accentError,
                          ),
                          onPressed: (_) async {
                            final res = await showConfirmationDialog(
                              context,
                              title: 'Delete Conversation',
                              question:
                                  'Are you sure you want to delete this conversation?',
                              okText: 'Delete',
                              cancelText: 'Cancel',
                              icon: StreamSvgIcon.delete(
                                color: chatTheme.colorTheme.accentError,
                              ),
                            );
                            if (res == true) {
                              await _controller.deleteChannel(channel);
                            }
                          },
                        ),
                    ],
                  ),
                  child: tile,
                );
              },
              onChannelTap: (channel) => Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (_) => StreamChannel(
                    channel: channel,
                    child: const ChannelPage(),
                  ),
                ),
              ),
            ),
          ),
        ),
      );
}

class ChannelPage extends StatelessWidget {
  const ChannelPage({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: const StreamChannelHeader(),
        body: Column(
          children: const <Widget>[
            Expanded(
              child: StreamMessageListView(),
            ),
            StreamMessageInput(),
          ],
        ),
      );
}
```

The above is the complete sample, and all you need for a basic implementation.

---

This page was last updated at 2025-08-15T14:15:48.772Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/flutter/v4/guides/slidable_channel_list_preview/](https://getstream.io/chat/docs/sdk/flutter/v4/guides/slidable_channel_list_preview/).