diff --git a/hypha/apply/users/admin_views.py b/hypha/apply/users/admin_views.py
index b8ae44a43d612fd97450a0ccc087c0f5a4604168..b1e8d9c6e24bd6ab6b9ce28f35b81bb63bb75555 100644
--- a/hypha/apply/users/admin_views.py
+++ b/hypha/apply/users/admin_views.py
@@ -1,10 +1,13 @@
+import django_filters
 from django.contrib.auth import get_user_model
+from django.contrib.auth.models import Group
 from django.core.paginator import Paginator
 from django.db.models import Q
 from django.shortcuts import render
 from django.utils.translation import gettext as _
 from django.views.decorators.vary import vary_on_headers
 from wagtail.admin.auth import any_permission_required
+from wagtail.admin.filters import WagtailFilterSet
 from wagtail.admin.forms.search import SearchForm
 from wagtail.core.compat import AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME
 
@@ -18,6 +21,33 @@ change_user_perm = "{0}.change_{1}".format(AUTH_USER_APP_LABEL, AUTH_USER_MODEL_
 delete_user_perm = "{0}.delete_{1}".format(AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME.lower())
 
 
+class UserFilterSet(WagtailFilterSet):
+    STATUS_CHOICES = (
+        ('inactive', 'INACTIVE'),
+        ('active', 'ACTIVE'),
+    )
+    roles = django_filters.ModelChoiceFilter(queryset=Group.objects.all(), label='Roles', method='filter_by_roles')
+    status = django_filters.ChoiceFilter(choices=STATUS_CHOICES, label='Status', method='filter_by_status')
+
+    class Meta:
+        model = User
+        fields = [
+            'roles',
+            'status'
+        ]
+
+    def filter_by_roles(self, queryset, name, value):
+        queryset = queryset.filter(groups__name=value)
+        return queryset
+
+    def filter_by_status(self, queryset, name, value):
+        if value == 'active':
+            return queryset.filter(is_active=True)
+        elif value == 'inactive':
+            return queryset.filter(is_active=False)
+        return queryset
+
+
 @any_permission_required(add_user_perm, change_user_perm, delete_user_perm)
 @vary_on_headers('X-Requested-With')
 def index(request):
@@ -30,7 +60,7 @@ def index(request):
 
     model_fields = [f.name for f in User._meta.get_fields()]
 
-    if 'q' in request.GET:
+    if request.GET.get('q', None):
         form = SearchForm(request.GET, placeholder=_("Search users"))
         if form.is_valid():
             q = form.cleaned_data['q']
@@ -61,6 +91,9 @@ def index(request):
     if not is_searching:
         users = User.objects.all().order_by('-is_active', 'full_name')
 
+    filters = UserFilterSet(request.GET, queryset=users, request=request)
+    users = filters.qs
+
     if 'ordering' in request.GET:
         ordering = request.GET['ordering']
 
@@ -71,21 +104,30 @@ def index(request):
     else:
         ordering = 'name'
 
+    user_count = users.count()
     paginator = Paginator(users, per_page=20)
     users = paginator.get_page(request.GET.get('p'))
 
     if request.headers.get('x-requested-with') == 'XMLHttpRequest':
         return render(request, "wagtailusers/users/results.html", {
             'users': users,
+            'user_count': user_count,
             'is_searching': is_searching,
             'query_string': q,
+            'filters': filters,
             'ordering': ordering,
+            'app_label': User._meta.app_label,
+            'model_name': User._meta.model_name,
         })
     else:
         return render(request, "wagtailusers/users/index.html", {
             'search_form': form,
             'users': users,
+            'user_count': user_count,
             'is_searching': is_searching,
             'ordering': ordering,
             'query_string': q,
+            'filters': filters,
+            'app_label': User._meta.app_label,
+            'model_name': User._meta.model_name,
         })
diff --git a/hypha/apply/users/templates/wagtailusers/users/index.html b/hypha/apply/users/templates/wagtailusers/users/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..fd28fb0f853ace65d13e46235be626bcfb50a80b
--- /dev/null
+++ b/hypha/apply/users/templates/wagtailusers/users/index.html
@@ -0,0 +1,44 @@
+{% extends "wagtailadmin/base.html" %}
+{% load i18n static wagtailadmin_tags %}
+{% block titletag %}{% trans "Users" %}{% endblock %}
+{% block extra_js %}
+    {{ block.super }}
+    <script>
+        window.headerSearch = {
+            {% if group %}
+                url: "{% url 'wagtailusers_groups:users' group.id %}",
+            {% else %}
+                url: "{% url 'wagtailusers_users:index' %}",
+            {% endif %}
+            termInput: "#id_q",
+            targetOutput: "#user-results"
+        }
+    </script>
+    <script>
+        window.wagtailConfig.BULK_ACTION_ITEM_TYPE = 'USER';
+    </script>
+    <script defer src="{% versioned_static 'wagtailadmin/js/bulk-actions.js' %}"></script>
+{% endblock %}
+
+{% block extra_css %}
+    {{ block.super }}
+    <link rel="stylesheet" href="{% static 'css/apply/wagtail_users_list.css' %}" type="text/css" />
+
+    {{ filters.form.media.css }}
+{% endblock %}
+
+{% block content %}
+    {% trans "Users" as users_str %}
+    {% trans "Add a user" as add_a_user_str %}
+
+    {% url "wagtailusers_users:add" as add_link %}
+    {% include "wagtailadmin/shared/header.html" with subtitle=group.name title=users_str action_url=add_link action_text=add_a_user_str icon="user" search_url="wagtailusers_users:index" %}
+
+    <div class="nice-padding">
+        <div id="user-results" class="users">
+            {% include "wagtailusers/users/results.html" %}
+        </div>
+        {% trans "Select all users in listing" as select_all_text %}
+        {% include 'wagtailadmin/bulk_actions/footer.html' with select_all_obj_text=select_all_text app_label=app_label model_name=model_name objects=users %}
+    </div>
+{% endblock %}
diff --git a/hypha/apply/users/templates/wagtailusers/users/list.html b/hypha/apply/users/templates/wagtailusers/users/list.html
index 449f1d102477bab09fd77e776ef9186bf37a7dd8..1ba5b89f7ce5284077d112e25fd76b4cf87cca4d 100644
--- a/hypha/apply/users/templates/wagtailusers/users/list.html
+++ b/hypha/apply/users/templates/wagtailusers/users/list.html
@@ -1,7 +1,8 @@
-{% load i18n wagtailusers_tags wagtailadmin_tags %}
+{% load i18n l10n wagtailusers_tags wagtailadmin_tags %}
 <table class="listing">
     <thead>
         <tr>
+            {% include 'wagtailadmin/bulk_actions/select_all_checkbox_cell.html' %}
             <th class="name">
                 {% trans "Name" %}
                 {% if ordering == "name" %}
@@ -32,8 +33,9 @@
     <tbody>
         {% for user in users %}
             <tr>
-                <td class="title" valign="top">
-                    <h2>
+                {% include "wagtailadmin/bulk_actions/listing_checkbox_cell.html" with obj_type="user" obj=user aria_labelledby_prefix="user_" aria_labelledby=user.pk|unlocalize aria_labelledby_suffix="_title" %}
+                <td id="user_{{ user.pk|unlocalize }}_title" class="title" valign="top">
+                    <h2 class="title-wrapper">
                         <span class="avatar small"><img src="{% avatar_url user size=25 %}" /></span>
                         <a href="{% url 'wagtailusers_users:edit' user.pk %}">{{ user.get_full_name|default:user.get_username }}</a>
                     </h2>
diff --git a/hypha/apply/users/templates/wagtailusers/users/results.html b/hypha/apply/users/templates/wagtailusers/users/results.html
new file mode 100644
index 0000000000000000000000000000000000000000..745afe7c11cf18048e497ad56d305e2e7758ac34
--- /dev/null
+++ b/hypha/apply/users/templates/wagtailusers/users/results.html
@@ -0,0 +1,47 @@
+{% load i18n wagtailadmin_tags %}
+<div class="users-list users-list--has-filters">
+    <div class="users-list__results">
+        {% if users %}
+            <h2 role="alert">
+            {% blocktrans trimmed count count=user_count %}
+                There is {{ user_count }} user
+            {% plural %}
+                There are {{ user_count }} users
+            {% endblocktrans %}
+            </h2>
+
+            {% if is_searching %}
+                {% search_other %}
+            {% endif %}
+            {% include "wagtailusers/users/list.html" %}
+
+            {# call pagination_nav with no linkurl, to generate general-purpose links like <div href="?p=2"/> #}
+            {% include "wagtailadmin/shared/pagination_nav.html" with items=users %}
+        {% else %}
+            <h2 role="alert">{% blocktrans trimmed %}Sorry, no users match "<em>{{ query_string }}</em>"{% endblocktrans %}</h2>
+            {% if is_searching %}
+                {% search_other %}
+            {% else %}
+                {% url 'wagtailusers_users:add' as wagtailusers_add_url %}
+                {% if group %}
+                    {% with group.name as group_name %}
+                        <p>{% blocktrans trimmed %}The {{ group_name }} group has no users configured. Why not <a href="{{ wagtailusers_add_url }}">add some</a>?{% endblocktrans %}</p>
+                    {% endwith %}
+                {% else %}
+                    <p>{% blocktrans trimmed %}There are no users configured. Why not <a href="{{ wagtailusers_add_url }}">add some</a>?{% endblocktrans %}</p>
+                {% endif %}
+            {% endif %}
+        {% endif %}
+    </div>
+    <div class="users-list__filters">
+        <h2>{% trans 'Filter' %}</h2>
+        <form method="get">
+            {% for filter in filters.form %}
+                {{ filter.label_tag }}
+                {{ filter }}
+                {{ filter.errors }}
+            {% endfor %}
+            <button class="button button-longrunning" type="submit">{% icon name="spinner" %}{% trans 'Apply filters' %}</button>
+        </form>
+    </div>
+</div>
diff --git a/hypha/static_src/src/sass/apply/wagtail_users_list.scss b/hypha/static_src/src/sass/apply/wagtail_users_list.scss
new file mode 100644
index 0000000000000000000000000000000000000000..0770fa211fe5b8ce7d78f281a461688ee3929cfa
--- /dev/null
+++ b/hypha/static_src/src/sass/apply/wagtail_users_list.scss
@@ -0,0 +1,27 @@
+// Abstracts
+@import 'abstracts/functions';
+@import 'abstracts/mixins';
+@import 'abstracts/variables';
+
+.users-list {
+    display: grid;
+    grid-template-columns: auto;
+    grid-column-gap: 50px;
+
+    &--has-filters {
+        grid-template-columns: auto 250px;
+    }
+
+    &__results {
+        grid-column-start: col-start 1 col-end 2;
+    }
+
+    &__filters {
+        grid-column-start: col-start -2 col-end -1;
+
+        button[type='submit'] {
+            display: block;
+            margin-top: 20px;
+        }
+    }
+}