Managed row dragging (grid-to-grid)
Reorder rows by dragging their grip, or move a row from one grid into another - both grids share a rowDragGroup, so the row leaves the source and lands in the target. The grid mutates its own data on drop and fires onRowDragEnd on the receiver.
A live, editable Svelte 5 data grid example from the SvGrid gallery (Rows & Cells). See the SvGrid documentation for the full API.
About this example
Managed row dragging in the Svelte 5 data grid, within one grid and between two. rowDragManaged turns every row into a drag source with a grip, rows reorder inside a grid, and because a Backlog and a Sprint grid share the same rowDragGroup a row can be dragged out of one and dropped into the other. The grid splices its own data on drop and onRowDragEnd fires on the receiving grid so you can mirror the move into your own state.
rowDragManaged turns every row into a drag source. Rows reorder within a grid, and - because both grids share the same rowDragGroup - a row can be dragged out of the Backlog and dropped into the Sprint (or back). The grid splices its own data on drop; onRowDragEnd fires on the receiving grid so you can mirror the move into your own state.
Imports, features and API used
Imports: @svgrid/grid
Columns: title (Task), priority (Priority), points (Pts)
Frequently asked questions
How do I let users reorder rows by dragging?
Set rowDragManaged on <SvGrid>. Each row gets a drag grip, dropping a row splices the grid's data into the new order, and onRowDragEnd tells you what moved so your own state can follow.
How do I drag a row from one grid into another?
Give both grids the same rowDragGroup string. A row dragged from one and dropped on the other leaves the source data and lands in the target at the drop position; onRowDragEnd fires on the receiver.
Does the grid mutate my array?
Yes, in managed mode the grid owns the splice so the drop is instant. If you need to control the move yourself, keep the data in your state and apply it from onRowDragEnd instead.
Related documentation
Source code (180-row-dragging.svelte)
<!-- Documented in: docs/help/rows/row-dragging.md -->
<script lang="ts">
/**
* 180. Managed row dragging (grid-to-grid)
* ----------------------------------------
* `rowDragManaged` turns every row into a drag source. Rows reorder within a
* grid, and - because both grids share the same `rowDragGroup` - a row can be
* dragged out of the Backlog and dropped into the Sprint (or back). The grid
* splices its own data on drop; `onRowDragEnd` fires on the receiving grid so
* you can mirror the move into your own state.
*/
import { SvGrid, type ColumnDef } from '@svgrid/grid'
type Task = { id: number; title: string; priority: 'High' | 'Medium' | 'Low'; points: number }
let backlog = $state<Task[]>([
{ id: 1, title: 'Design empty states', priority: 'Medium', points: 3 },
{ id: 2, title: 'Keyboard nav audit', priority: 'High', points: 5 },
{ id: 3, title: 'Dark theme polish', priority: 'Low', points: 2 },
{ id: 4, title: 'CSV export edge cases', priority: 'Medium', points: 3 },
{ id: 5, title: 'Virtualization stress test', priority: 'High', points: 8 },
])
let sprint = $state<Task[]>([
{ id: 6, title: 'Ship filter row', priority: 'High', points: 5 },
{ id: 7, title: 'Pivot subtotals', priority: 'Medium', points: 3 },
])
let lastMove = $state<string>('Drag a row within a grid to reorder, or across to move it.')
const columns: ColumnDef<any, Task>[] = [
{ field: 'title', header: 'Task', width: 210 },
{ field: 'priority', header: 'Priority', width: 100 },
{ field: 'points', header: 'Pts', width: 64, align: 'right' },
]
function onEnd(where: 'Backlog' | 'Sprint') {
return (e: { row: Task; toIndex: number; sameGrid: boolean }) => {
lastMove = e.sameGrid
? `Reordered "${e.row.title}" within ${where} → position ${e.toIndex + 1}`
: `Moved "${e.row.title}" into ${where} → position ${e.toIndex + 1}`
}
}
</script>
<section class="flex flex-col flex-1 min-h-0 gap-3">
<p class="text-sm shrink-0" style="color: var(--sg-fg);">
<strong>Drag any row</strong> by its grip (the <code>⠿</code> in the number
column). Reorder inside a grid, or drag a row <strong>across</strong> to the
other grid - both share <code>rowDragGroup="sprint-board"</code>, so the row
leaves one and lands in the other. Drop below the last row to append.
</p>
<div
class="shrink-0 text-xs rounded-md px-3 py-2"
style="color: var(--sg-fg); background: var(--sg-header-bg); border: 1px solid var(--sg-border);"
>
{lastMove}
</div>
<div class="boards grid grid-cols-2 gap-4 flex-1 min-h-0">
<div class="flex flex-col min-h-0">
<h3 class="text-sm font-semibold mb-1 shrink-0" style="color: var(--sg-fg);">Backlog</h3>
<div class="flex-1 min-h-0">
<SvGrid responsive={true}
columnResize
data={backlog}
columns={columns}
showRowNumbers={true}
rowDragManaged={true}
rowDragGroup="sprint-board"
onRowDragEnd={onEnd('Backlog')}
rowHeight={40}
containerHeight="100%"
fitColumns={true}
/>
</div>
</div>
<div class="flex flex-col min-h-0">
<h3 class="text-sm font-semibold mb-1 shrink-0" style="color: var(--sg-fg);">Sprint</h3>
<div class="flex-1 min-h-0">
<SvGrid responsive={true}
columnResize
data={sprint}
columns={columns}
showRowNumbers={true}
rowDragManaged={true}
rowDragGroup="sprint-board"
onRowDragEnd={onEnd('Sprint')}
rowHeight={40}
containerHeight="100%"
fitColumns={true}
/>
</div>
</div>
</div>
</section>
<style>
/* Phone: two boards side by side are ~170px each. Stack them; the shared
mobile layer floors each grid pane, so both stay usable and the page
scrolls. */
@media (max-width: 639px) {
.boards { grid-template-columns: minmax(0, 1fr); }
}
</style>More Rows & Cells examples
- External drop zones (row drag) - Drag a row out of the grid onto any element - an Archive or Delete bucket - via the rowDropZone action. The row leaves the grid and the zone's onDrop handles it. In-grid reorder still works.
- Custom cells + themes - Avatars, sparklines, progress bars, density toggle, dark mode, full a11y.
- Sparkline cells - In-cell mini charts as a first-class column type: set `sparkline` on a number-array column and the grid paints an inline SVG. Line, area, bar (with +/- coloring), and win/loss - no chart library, no custom snippet.
- Conditional formatting (engine) - Excel-style value-driven cell coloring as a declarative `conditionalFormats` engine prop: gradient heat maps (alpha ramp, zero-centred, banded, column-comparison), in-cell data bars, icon sets, and predicate rules - scoped per column, no per-cell snippet.
- Conditional styling - Support-ticket triage board: rowClass highlights SLA breach + at-risk rows with side-bar accents; cellClass paints priority pills, status badges, agent-load progress bars, and CSAT highlights.