Skip to main content
Version: v4


A Widget For Controlling A List Of Users

Find the documentation here


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 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 SortOptions and other pagination-related parameters.

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.

void initState() {

void dispose() {

The StreamUserListController is basically a PagedValueNotifier that notifies you when the list of users has changed. You can use a PagedValueListenableBuilder to build your UI depending on the latest users.

Widget build(BuildContext context) => Scaffold(
body: PagedValueListenableBuilder<int, User>(
valueListenable: userListController,
builder: (context, value, child) {
return value.when(
(users, nextPageKey, error) => LazyLoadScrollView(
onEndOfPage: () async {
if (nextPageKey != null) {
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: () {
child: Text(error.message),
return CircularProgressIndicator();

final _item = users[index];
return ListTile(
title: Text( ?? ''),
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 widget to load more data when the user scrolls to the bottom of the list.

Did you find this page helpful?