diff --git a/app/Actions/Queries/WebhooksAllPaginatedAndSorted.php b/app/Actions/Queries/WebhooksAllPaginatedAndSorted.php
new file mode 100644
index 000000000..86e4e2040
--- /dev/null
+++ b/app/Actions/Queries/WebhooksAllPaginatedAndSorted.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace BookStack\Actions\Queries;
+
+use BookStack\Actions\Webhook;
+use Illuminate\Pagination\LengthAwarePaginator;
+
+/**
+ * Get all the webhooks in the system in a paginated format.
+ */
+class WebhooksAllPaginatedAndSorted
+{
+    /**
+     * @param array{sort: string, order: string, search: string} $sortData
+     */
+    public function run(int $count, array $sortData): LengthAwarePaginator
+    {
+        $sort = $sortData['sort'];
+
+        $query = Webhook::query()->select(['*'])
+            ->withCount(['trackedEvents'])
+            ->orderBy($sort, $sortData['order']);
+
+        if ($sortData['search']) {
+            $term = '%' . $sortData['search'] . '%';
+            $query->where(function ($query) use ($term) {
+                $query->where('name', 'like', $term)
+                    ->orWhere('endpoint', 'like', $term);
+            });
+        }
+
+        return $query->paginate($count);
+    }
+}
diff --git a/app/Auth/Queries/AllRolesPaginatedAndSorted.php b/app/Auth/Queries/RolesAllPaginatedAndSorted.php
similarity index 96%
rename from app/Auth/Queries/AllRolesPaginatedAndSorted.php
rename to app/Auth/Queries/RolesAllPaginatedAndSorted.php
index add1e9e54..6abbfd1ad 100644
--- a/app/Auth/Queries/AllRolesPaginatedAndSorted.php
+++ b/app/Auth/Queries/RolesAllPaginatedAndSorted.php
@@ -8,7 +8,7 @@ use Illuminate\Pagination\LengthAwarePaginator;
 /**
  * Get all the roles in the system in a paginated format.
  */
-class AllRolesPaginatedAndSorted
+class RolesAllPaginatedAndSorted
 {
     /**
      * @param array{sort: string, order: string, search: string} $sortData
diff --git a/app/Auth/Queries/AllUsersPaginatedAndSorted.php b/app/Auth/Queries/UsersAllPaginatedAndSorted.php
similarity index 97%
rename from app/Auth/Queries/AllUsersPaginatedAndSorted.php
rename to app/Auth/Queries/UsersAllPaginatedAndSorted.php
index 29e58fe09..3a64cc800 100644
--- a/app/Auth/Queries/AllUsersPaginatedAndSorted.php
+++ b/app/Auth/Queries/UsersAllPaginatedAndSorted.php
@@ -11,7 +11,7 @@ use Illuminate\Pagination\LengthAwarePaginator;
  * user is assumed to be trusted. (Admin users).
  * Email search can be abused to extract email addresses.
  */
-class AllUsersPaginatedAndSorted
+class UsersAllPaginatedAndSorted
 {
     /**
      * @param array{sort: string, order: string, search: string} $sortData
diff --git a/app/Http/Controllers/RoleController.php b/app/Http/Controllers/RoleController.php
index d022bf35d..0e13a9fb3 100644
--- a/app/Http/Controllers/RoleController.php
+++ b/app/Http/Controllers/RoleController.php
@@ -3,7 +3,7 @@
 namespace BookStack\Http\Controllers;
 
 use BookStack\Auth\Permissions\PermissionsRepo;
-use BookStack\Auth\Queries\AllRolesPaginatedAndSorted;
+use BookStack\Auth\Queries\RolesAllPaginatedAndSorted;
 use BookStack\Auth\Role;
 use BookStack\Exceptions\PermissionsException;
 use Exception;
@@ -32,7 +32,7 @@ class RoleController extends Controller
             'order'  => setting()->getForCurrentUser('roles_sort_order', 'asc'),
         ];
 
-        $roles = (new AllRolesPaginatedAndSorted())->run(20, $listDetails);
+        $roles = (new RolesAllPaginatedAndSorted())->run(20, $listDetails);
         $roles->appends(['search' => $listDetails['search']]);
 
         $this->setPageTitle(trans('settings.roles'));
diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php
index bd69aa8f5..77be07533 100644
--- a/app/Http/Controllers/UserController.php
+++ b/app/Http/Controllers/UserController.php
@@ -3,7 +3,7 @@
 namespace BookStack\Http\Controllers;
 
 use BookStack\Auth\Access\SocialAuthService;
-use BookStack\Auth\Queries\AllUsersPaginatedAndSorted;
+use BookStack\Auth\Queries\UsersAllPaginatedAndSorted;
 use BookStack\Auth\Role;
 use BookStack\Auth\User;
 use BookStack\Auth\UserRepo;
@@ -42,7 +42,7 @@ class UserController extends Controller
             'order'  => setting()->getForCurrentUser('users_sort_order', 'asc'),
         ];
 
-        $users = (new AllUsersPaginatedAndSorted())->run(20, $listDetails);
+        $users = (new UsersAllPaginatedAndSorted())->run(20, $listDetails);
 
         $this->setPageTitle(trans('settings.users'));
         $users->appends(['search' => $listDetails['search']]);
@@ -251,7 +251,7 @@ class UserController extends Controller
      */
     public function changeSort(Request $request, string $id, string $type)
     {
-        $validSortTypes = ['books', 'bookshelves', 'shelf_books', 'users', 'roles'];
+        $validSortTypes = ['books', 'bookshelves', 'shelf_books', 'users', 'roles', 'webhooks'];
         if (!in_array($type, $validSortTypes)) {
             return redirect()->back(500);
         }
@@ -322,7 +322,7 @@ class UserController extends Controller
         //   Probably better to do a simple validation here then validate at usage.
         $validSorts = [
             'name', 'created_at', 'updated_at', 'default', 'email', 'last_activity_at', 'display_name',
-            'users_count', 'permissions_count',
+            'users_count', 'permissions_count', 'endpoint', 'active',
         ];
         if (!in_array($sort, $validSorts)) {
             $sort = 'name';
diff --git a/app/Http/Controllers/WebhookController.php b/app/Http/Controllers/WebhookController.php
index 264921dfc..23120c7e4 100644
--- a/app/Http/Controllers/WebhookController.php
+++ b/app/Http/Controllers/WebhookController.php
@@ -3,6 +3,7 @@
 namespace BookStack\Http\Controllers;
 
 use BookStack\Actions\ActivityType;
+use BookStack\Actions\Queries\WebhooksAllPaginatedAndSorted;
 use BookStack\Actions\Webhook;
 use Illuminate\Http\Request;
 
@@ -18,16 +19,23 @@ class WebhookController extends Controller
     /**
      * Show all webhooks configured in the system.
      */
-    public function index()
+    public function index(Request $request)
     {
-        $webhooks = Webhook::query()
-            ->orderBy('name', 'desc')
-            ->with('trackedEvents')
-            ->get();
+        $listDetails = [
+            'search' => $request->get('search', ''),
+            'sort'   => setting()->getForCurrentUser('webhooks_sort', 'name'),
+            'order'  => setting()->getForCurrentUser('webhooks_sort_order', 'asc'),
+        ];
+
+        $webhooks = (new WebhooksAllPaginatedAndSorted())->run(20, $listDetails);
+        $webhooks->appends(['search' => $listDetails['search']]);
 
         $this->setPageTitle(trans('settings.webhooks'));
 
-        return view('settings.webhooks.index', ['webhooks' => $webhooks]);
+        return view('settings.webhooks.index', [
+            'webhooks'    => $webhooks,
+            'listDetails' => $listDetails,
+        ]);
     }
 
     /**
diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php
index e8978d41e..f4204dd68 100755
--- a/resources/lang/en/settings.php
+++ b/resources/lang/en/settings.php
@@ -247,6 +247,8 @@ return [
 
     // Webhooks
     'webhooks' => 'Webhooks',
+    'webhooks_index_desc' => 'Webhooks are a way to send data to external URLs when certain actions and events occur within the system which allows event-based integration with external platforms such as messaging or notification systems.',
+    'webhooks_x_trigger_events' => '1 trigger event|:count trigger events',
     'webhooks_create' => 'Create New Webhook',
     'webhooks_none_created' => 'No webhooks have yet been created.',
     'webhooks_edit' => 'Edit Webhook',
diff --git a/resources/sass/_components.scss b/resources/sass/_components.scss
index 667c26388..acb45100f 100644
--- a/resources/sass/_components.scss
+++ b/resources/sass/_components.scss
@@ -969,4 +969,17 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
 }
 .item-list-row:hover .item-list-row-toggle-all {
   visibility: visible;
+}
+
+.status-indicator-active, .status-indicator-inactive {
+  width: 8px;
+  height: 8px;
+  border-radius: 50%;
+  display: inline-block;
+}
+.status-indicator-active {
+  background-color: $positive;
+}
+.status-indicator-inactive {
+  background-color: $negative;
 }
\ No newline at end of file
diff --git a/resources/views/common/status-indicator.blade.php b/resources/views/common/status-indicator.blade.php
new file mode 100644
index 000000000..ba9b1b463
--- /dev/null
+++ b/resources/views/common/status-indicator.blade.php
@@ -0,0 +1,3 @@
+<span title="{{ trans('common.status_' . ($status ? 'active' : 'inactive')) }}"
+      class="status-indicator-{{ $status ? 'active' : 'inactive' }}"
+></span>
\ No newline at end of file
diff --git a/resources/views/settings/roles/index.blade.php b/resources/views/settings/roles/index.blade.php
index 6aeb16f92..7e3d5b852 100644
--- a/resources/views/settings/roles/index.blade.php
+++ b/resources/views/settings/roles/index.blade.php
@@ -31,6 +31,8 @@
                         'display_name' => trans('common.sort_name'),
                         'users_count' => trans('settings.roles_assigned_users'),
                         'permissions_count' => trans('settings.roles_permissions_provided'),
+                        'created_at' => trans('common.sort_created_at'),
+                        'updated_at' => trans('common.sort_updated_at'),
                     ], 'order' => $listDetails['order'], 'sort' => $listDetails['sort'], 'type' => 'roles'])
                 </div>
             </div>
diff --git a/resources/views/settings/webhooks/index.blade.php b/resources/views/settings/webhooks/index.blade.php
index bbe58453f..09b2ee770 100644
--- a/resources/views/settings/webhooks/index.blade.php
+++ b/resources/views/settings/webhooks/index.blade.php
@@ -8,48 +8,51 @@
 
         <div class="card content-wrap auto-height">
 
-            <div class="grid half v-center">
+            <div class="flex-container-row items-center justify-space-between wrap">
                 <h1 class="list-heading">{{ trans('settings.webhooks') }}</h1>
 
-                <div class="text-right">
+                <div>
                     <a href="{{ url("/settings/webhooks/create") }}"
                        class="button outline">{{ trans('settings.webhooks_create') }}</a>
                 </div>
             </div>
 
-            @if(count($webhooks) > 0)
+            <p class="text-muted">{{ trans('settings.webhooks_index_desc') }}</p>
 
-                <table class="table">
-                    <tr>
-                        <th>{{ trans('common.name') }}</th>
-                        <th width="100">{{ trans('settings.webhook_events_table_header') }}</th>
-                        <th width="100">{{ trans('common.status') }}</th>
-                    </tr>
+            <div class="flex-container-row items-center justify-space-between gap-m mt-m mb-l wrap">
+                <div>
+                    <div class="block inline mr-xs">
+                        <form method="get" action="{{ url("/settings/webhooks") }}">
+                            <input type="text" name="search" placeholder="{{ trans('common.search') }}" @if($listDetails['search']) value="{{$listDetails['search']}}" @endif>
+                        </form>
+                    </div>
+                </div>
+                <div class="justify-flex-end">
+                    @include('common.sort', ['options' => [
+                        'name' => trans('common.sort_name'),
+                        'endpoint'  => trans('settings.webhooks_endpoint'),
+                        'created_at' => trans('common.sort_created_at'),
+                        'updated_at' => trans('common.sort_updated_at'),
+                        'active'     => trans('common.status'),
+                    ], 'order' => $listDetails['order'], 'sort' => $listDetails['sort'], 'type' => 'webhooks'])
+                </div>
+            </div>
+
+            @if(count($webhooks) > 0)
+                <div class="item-list">
                     @foreach($webhooks as $webhook)
-                        <tr>
-                            <td>
-                                <a href="{{ $webhook->getUrl() }}">{{ $webhook->name }}</a> <br>
-                                <span class="small text-muted italic">{{ $webhook->endpoint }}</span>
-                            </td>
-                            <td>
-                                @if($webhook->tracksEvent('all'))
-                                    {{ trans('settings.webhooks_events_all') }}
-                                @else
-                                    {{ $webhook->trackedEvents->count() }}
-                                @endif
-                            </td>
-                            <td>
-                                {{ trans('common.status_' . ($webhook->active ? 'active' : 'inactive')) }}
-                            </td>
-                        </tr>
+                        @include('settings.webhooks.parts.webhooks-list-item', ['webhook' => $webhook])
                     @endforeach
-                </table>
+                </div>
             @else
                 <p class="text-muted empty-text px-none">
                     {{ trans('settings.webhooks_none_created') }}
                 </p>
             @endif
 
+            <div class="my-m">
+                {{ $webhooks->links() }}
+            </div>
 
         </div>
     </div>
diff --git a/resources/views/settings/webhooks/parts/webhooks-list-item.blade.php b/resources/views/settings/webhooks/parts/webhooks-list-item.blade.php
new file mode 100644
index 000000000..5b7d135eb
--- /dev/null
+++ b/resources/views/settings/webhooks/parts/webhooks-list-item.blade.php
@@ -0,0 +1,18 @@
+<div class="item-list-row py-s">
+    <div class="flex-container-row">
+        <div class="flex-2 py-xxs px-m flex-container-row items-center gap-s">
+            @include('common.status-indicator', ['status' => $webhook->active])
+            <a href="{{ $webhook->getUrl() }}">{{ $webhook->name }}</a>
+        </div>
+        <div class="flex py-xxs px-m text-right text-muted">
+            @if($webhook->tracksEvent('all'))
+                {{ trans('settings.webhooks_events_all') }}
+            @else
+                {{ trans_choice('settings.webhooks_x_trigger_events', $webhook->tracked_events_count, ['count' =>  $webhook->tracked_events_count]) }}
+            @endif
+        </div>
+    </div>
+    <div class="px-m py-xxs text-muted italic text-limit-lines-1">
+        <small>{{ $webhook->endpoint }}</small>
+    </div>
+</div>
\ No newline at end of file