Implementing Sortable Table with Toggle Arrows in Laravel
Step 1: Create the Controller Logic
Create or update a controller UserController to handle sorting logic. Here’s an example for a users table:
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
class UserController extends Controller
{
public function index(Request $request)
{
$sortBy = $request->query('sort_by', 'name'); // Default sort by name
$sortDirection = $request->query('direction', 'asc'); // Default ascending
// Validate sort_by to prevent SQL injection
$validColumns = ['name', 'email', 'created_at'];
if (!in_array($sortBy, $validColumns)) {
$sortBy = 'name';
}
// Toggle sort direction for the next click
$direction = $sortDirection === 'asc' ? 'desc' : 'asc';
// Fetch sorted and paginated data
$users = User::orderBy($sortBy, $sortDirection)->paginate(10);
return view('users.index', compact('users', 'sortBy', 'sortDirection', 'direction'));
}
}
Explanation
- Query Parameters: sort_by determines the column to sort, and direction sets the sort order (asc or desc).
- Validation: Only allow specific columns to prevent SQL injection.
- Toggle Direction: The $direction variable is set to the opposite of the current sort direction for the next click.
- Pagination: Use paginate to limit results per page.
Step 2: Define the Route
In routes/web.php
, add a route for the controller:
use App\Http\Controllers\UserController;
Route::get('/users', [UserController::class, 'index'])->name('users.index');
Step 3: Create the View with Toggle Arrows
Create a Blade view at resources/views/users/index.blade.php
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sortable User Table</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
.sort-icon::after {
content: '';
display: inline-block;
width: 0;
height: 0;
margin-left: 5px;
vertical-align: middle;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
}
.sort-asc::after {
border-bottom: 4px solid #000;
}
.sort-desc::after {
border-top: 4px solid #000;
}
</style>
</head>
<body>
<div class="container mt-5">
<h2>Sortable User Table</h2>
<table class="table table-bordered">
<thead>
<tr>
<th>
<a href="{{ route('users.index', ['sort_by' => 'name', 'direction' => ($sortBy == 'name' ? $direction : 'asc')]) }}"
class="sort-link {{ $sortBy == 'name' ? ($sortDirection == 'asc' ? 'sort-asc' : 'sort-desc') : '' }}">
Name
</a>
</th>
<th>
<a href="{{ route('users.index', ['sort_by' => 'email', 'direction' => ($sortBy == 'email' ? $direction : 'asc')]) }}"
class="sort-link {{ $sortBy == 'email' ? ($sortDirection == 'asc' ? 'sort-asc' : 'sort-desc') : '' }}">
Email
</a>
</th>
<th>
<a href="{{ route('users.index', ['sort_by' => 'created_at', 'direction' => ($sortBy == 'created_at' ? $direction : 'asc')]) }}"
class="sort-link {{ $sortBy == 'created_at' ? ($sortDirection == 'asc' ? 'sort-asc' : 'sort-desc') : '' }}">
Created At
</a>
</th>
</tr>
</thead>
<tbody>
@foreach ($users as $user)
<tr>
<td>{{ $user->name }}</td>
<td>{{ $user->email }}</td>
<td>{{ $user->created_at }}</td>
</tr>
@endforeach
</tbody>
</table>
{{ $users->appends(['sort_by' => $sortBy, 'direction' => $sortDirection])->links() }}
</div>
</body>
</html>
Explanation
- Sort Links: Each column header is a link that passes sort_by and direction query parameters. If the column is currently sorted, it uses the toggled $direction; otherwise, it defaults to asc.
- Toggle Arrows: CSS classes sort-asc and sort-desc add up/down arrows using pseudo-elements. The class is applied based on the current $sortBy and $sortDirection.
- Pagination Links: The appends method ensures sort parameters persist across pagination.

Step 4: How It Works
- Clicking a column header sends a request with sort_by (e.g., name) and direction (e.g., asc).
- The controller sorts the data using orderBy and passes the current sort state to the view.
- The view displays arrows indicating the sort direction and toggles the direction for the next click.
- Pagination links maintain the sort parameters.
Step 5: Testing
- Ensure your Laravel app is running (php artisan serve).
- Visit /users in your browser.
- Click column headers to sort. Arrows will indicate the current sort direction and toggle on subsequent clicks.
Conclusion
This implementation provides a clean, secure, and reusable way to add sortable tables with toggle arrows in Laravel.