Install the Package
composer require aymericcucherousset/ux-sortable
Ensure symfony/stimulus-bundle and symfony/ux-live-component are installed.
Register Stimulus Bundle
Add to config/bundles.php:
Symfony\Stimulus\Bridge\SymfonyBridge::class => ['all' => true],
First Use Case: Basic Sortable List
Create a Twig component (TestList.html.twig) with sortable_attributes:
<ul {{ sortable_attributes({ animation: 200 }) }}>
{% for item in items %}
<li data-id="{{ item.id }}">{{ item.name }}</li>
{% endfor %}
</ul>
LiveComponent Integration
Add a LiveListener in your component class to handle reorder events:
#[LiveListener('reorder.end')]
public function onReorder(array $order): void {
// Update state or persist changes
}
Dynamic List Reordering
sortable_attributes with a prefix (e.g., reorder) to customize event names.{{ sortable_attributes({ prefix: 'task' }) }} emits task.end.State Management
$items array in LiveListener to reflect changes.reorder.end to persist order.Nested Sorting
<ul> tags and apply sortable_attributes to each level.data-id attributes for hierarchical items.sortable_attributes for reusable templates.data-id uniqueness to prevent sorting errors.#[LiveListener('reorder.end')]
public function updateOrder(array $order): void {
$this->items = array_map(fn($id) => $this->findItem($id), $order);
$this->persistOrder($this->items); // Call API or save to DB
}
Event Prefix Conflicts
prefix in sortable_attributes doesn’t clash with other Stimulus controllers.Custom Events.Missing data-id
data-id is missing.{% if not item.id %}{{ abort(400, 'Missing ID') }}{% endif %}
Animation Lag
animation values (e.g., 500) may cause UI jank.0 for instant transitions in performance-critical apps.Event Listener Not Triggering?
LiveListener event name matches sortable_attributes prefix (e.g., reorder.end).console.log(Stimulus.controllers);
State Not Updating?
LiveProp is marked as writable: true:
#[LiveProp(writable: true)]
public array $items = [];
Custom Stimulus Controller Override default behavior by extending the Stimulus controller:
// assets/controllers/sortable_controller.js
import { SortableController } from '@symfony/ux-sortable';
export default class extends SortableController {
connect() {
super.connect();
this.element.addEventListener('click', () => console.log('Custom logic'));
}
}
Twig Global Helper
Add to TwigExtension for project-wide usage:
$twig->addFunction(new \Twig\TwigFunction('sortable', [$this, 'renderSortable']));
Server-Side Validation
Validate reorder payloads in LiveListener:
#[LiveListener('reorder.end')]
public function validateOrder(array $order): void {
if (count($order) !== count($this->items)) {
throw new \RuntimeException('Invalid order length');
}
}
handle: 'float' for smoother drag-and-drop with many items.How can I help you explore Laravel packages today?