A Laravel Nova 5 package for drag-and-drop and arrow-based sorting of resources.
- Drag-and-drop reordering via SortableJS
- Up/down arrow buttons for precise ordering
- Visual feedback: green border on moved row, red border on displaced row
- Toast notifications on success/error
- Publishable config for global defaults
- No full page reload — instant DOM updates
- PHP ^8.2
- Laravel Nova ^5.0
composer require almirhodzic/nova-sortable-5The service provider is auto-discovered. No manual registration needed.
php artisan vendor:publish --tag=frontbyte-nova-sortable-configThis creates config/frontbyte-nova-sortable.php where you can set global defaults.
New table:
Schema::create('services', function (Blueprint $table) {
$table->id();
$table->unsignedInteger('sort_order')->default(0);
// ... other columns
$table->timestamps();
});Existing table — create a migration to add the column:
php artisan make:migration add_sort_order_to_services_tableSchema::table('services', function (Blueprint $table) {
$table->unsignedInteger('sort_order')->default(0)->after('id');
});Then run the migration:
php artisan migrateAfter migrating, you can initialize the order values for existing rows:
php artisan tinkerApp\Models\Service::query()->each(function ($service, $index) {
$service->update(['sort_order' => $index + 1]);
});use AlmirHodzic\NovaSortable5\HasSortableRows;
class Service extends Model
{
use HasSortableRows;
protected string $sortableColumn = 'sort_order';
}The $sortableColumn property is optional. If omitted, it uses the default_column from the config (default: order).
use AlmirHodzic\NovaSortable5\Sortable;
use AlmirHodzic\NovaSortable5\SortableResource;
class Service extends Resource
{
use SortableResource;
public function fields(NovaRequest $request): array
{
return [
Sortable::make('Order', 'sort_order'),
// ... other fields
];
}
}The SortableResource trait ensures Nova sorts by your sortable column by default, preventing conflicts with drag-and-drop.
Tip: If you're adding this package to an existing resource with pre-existing rows, their
sort_ordervalues will initially all be0. Simply perform a single drag-and-drop reorder in the admin panel — the package will automatically recalculate and persist thesort_orderfor all rows in the table.
After publishing, edit config/frontbyte-nova-sortable.php:
return [
// Default database column for sorting
'default_column' => 'sort_order',
// Default sort direction: 'asc' or 'desc'
'order_direction' => 'asc',
// Show the drag handle (bars icon)
'show_drag_handle' => true,
// Show up/down arrow buttons
'show_order_arrows' => true,
// Show the order number
'show_order_number' => true,
// Show toast messages after reordering
'show_toast' => true,
// Authentication guards for the API routes
'guards' => ['web'],
];All config values serve as global defaults. You can override them per field (see below).
You can override config defaults per resource by chaining methods on the Sortable field:
| Method | Description |
|---|---|
showDragHandle() / hideDragHandle() |
Toggle drag handle visibility |
showSortArrows() / hideSortArrows() |
Toggle arrow buttons |
showOrderNumber() / hideOrderNumber() |
Toggle order number display |
showToast() / hideToast() |
Toggle success/error toast messages |
By default, the package automatically assigns the next order value (max + 1) when creating a new model. This means every new entry is added to the end of the list.
If you want to control the order value manually (e.g. via a form field), you can disable this:
Sortable::make('Order', 'sort_order')
->autoAssignOnCreate(false)With auto-assign disabled, you are responsible for setting the sort_order value yourself:
Service::create([
'name' => 'My Service',
'sort_order' => 5, // must be set manually
]);Drag-and-drop: Grab the bars icon and drag a row to its new position. All affected rows are reordered in a single API call.
Arrow buttons: Click the up/down arrows to swap a row with its neighbor. Only the two affected rows are swapped.
Visual feedback: After sorting, the moved row flashes green and the displaced row flashes red — providing clear visual confirmation of what changed.
No page reload: All updates happen via API calls with instant DOM manipulation. The order numbers update automatically.
The HasSortableRows trait provides:
// Auto-assigns the next order value when creating a model
$service = Service::create(['name' => 'New Service']);
// sort_order is automatically set to max + 1
// Move a model to a specific position (re-indexes other rows)
$service->moveToPosition(1);
// Query scope for custom ordering
Service::orderBySortable('desc')->get();
// Get the sortable column name
$service->getSortableColumn(); // 'sort_order'MIT License. See LICENSE for details.
