---
id: stream_user_list_controller
sidebar_position: 5
title: StreamUserListController
---

A Widget For Controlling A List Of Users

Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamUserListController-class.html)

### Background

The `StreamUserListController` is a controller class that allows you to control a list of users.
`StreamUserListController` is a required parameter of the `StreamUserListView` widget.
Check the [`StreamUserListView` documentation](../03-stream_chat_flutter/stream_user_list_view.mdx) to read more about that.

### Basic Example

Building a custom user list is a very common task. Here is an example of how to use the `StreamUserListController` to build a simple list with pagination.

First of all we should create an instance of the `StreamUserListController` and provide it with the `StreamChatClient` instance.
You can also add a `Filter`, a list of `SortOption`s and other pagination-related parameters.

```dart
class UserListPageState extends State<UserListPage> {
  /// Controller used for loading more data and controlling pagination in
  /// [StreamUserListController].
  late final userListController = StreamUserListController(
    client: StreamChatCore.of(context).client,
  );
```

Make sure you call `userListController.doInitialLoad()` to load the initial data and `userListController.dispose()` when the controller is no longer required.

```dart
@override
void initState() {
  userListController.doInitialLoad();
  super.initState();
}

@override
void dispose() {
  userListController.dispose();
  super.dispose();
}
```

The `StreamUserListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of users has changed.
You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest users.

```dart
@override
Widget build(BuildContext context) => Scaffold(
      body: PagedValueListenableBuilder<int, List<User>>(
        valueListenable: userListController,
        builder: (context, value, child) {
          return value.when(
            (users, nextPageKey, error) => LazyLoadScrollView(
              onEndOfPage: () async {
                if (nextPageKey != null) {
                  userListController.loadMore(nextPageKey);
                }
              },
              child: ListView.builder(
                /// We're using the users length when there are no more
                /// pages to load and there are no errors with pagination.
                /// In case we need to show a loading indicator or and error
                /// tile we're increasing the count by 1.
                itemCount: (nextPageKey != null || error != null)
                    ? users.length + 1
                    : users.length,
                itemBuilder: (BuildContext context, int index) {
                  if (index == users.length) {
                    if (error != null) {
                      return TextButton(
                          onPressed: () {
                            userListController.retry();
                          },
                          child: Text(error.message),
                        );
                    }
                    return CircularProgressIndicator();
                  }

                  final _item = users[index];
                  return ListTile(
                    title: Text(_item.name ?? ''),
                  );
                },
              ),
            ),
            loading: () => const Center(
              child: SizedBox(
                height: 100,
                width: 100,
                child: CircularProgressIndicator(),
              ),
            ),
            error: (e) => Center(
              child: Text(
                'Oh no, something went wrong. '
                'Please check your config. $e',
              ),
            ),
          );
        },
      ),
    );
```

In this case we're using the [`LazyLoadScrollView`](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list.