Your search did not match any results.


The Sortable widget allows users to reorder elements using drag-and-drop. In this demo, two different Sortables are used. You can identify them in the code by the class attribute:

  • sortable-lists
    This Sortable allows users to reorder card lists. The widget nests <div> elements that represent the lists. The handle option specifies that lists can be dragged by their titles. To correctly animate items being reordered, Sortable requires the item orientation. The itemOrientation option is set to "horizontal" because card lists are orientated horizontally.

  • sortable-cards
    This Sortable allows users to reorder cards. The widget nests <div> elements that represent all cards in a specific list. All Sortables are added to the same group to allow users to move cards between lists.

In addition to Sortable, this kanban board implementation uses the ScrollView widget. The widget's instance with the scrollable-board class allows you to scroll the board left to right. The widget's instance with the scrollable-list class makes lists scrollable.

@model DevExtreme.MVC.Demos.ViewModels.KanbanViewModel @using DevExtreme.MVC.Demos.Models.TreeList; <div id="kanban"> @(Html.DevExtreme().ScrollView() .ElementAttr("class", "scrollable-board") .Direction(ScrollDirection.Horizontal) .ShowScrollbar(ShowScrollbarMode.Always) .Content( Html.DevExtreme().Sortable() .ElementAttr("class", "sortable-lists") .ItemOrientation(Orientation.Horizontal) .MoveItemOnDrop(true) .Handle(".list-title") .Content(@<text> @foreach(var status in Model.Statuses) { @CreateList(status, Model.Tasks.Where(t => t.Task_Status == status)) } </text>).ToString() ) ) </div> @helper CreateList(string status, IEnumerable<EmployeeTask> tasks) { <div class="list"> <div class="list-title dx-theme-text-color">@status</div> @(Html.DevExtreme().ScrollView() .ElementAttr("class", "scrollable-list") .Direction(ScrollDirection.Vertical) .ShowScrollbar(ShowScrollbarMode.Always) .Content( Html.DevExtreme().Sortable() .ElementAttr("class", "sortable-cards") .ItemOrientation(Orientation.Vertical) .MoveItemOnDrop(true) .Group("tasksGroup") .Content(@<text> @CreateCards(tasks) </text>).ToString() ) ) </div>} @helper CreateCards(IEnumerable<EmployeeTask> tasks) { foreach(var task in tasks) { <div class="card dx-card dx-theme-text-color dx-theme-background-color"> <div class="card-priority priority-@((int)task.Task_Priority + 1)"></div> <div class="card-subject">@task.Task_Subject</div> <div class="card-assignee">@Model.Employees.Where(e => e.ID == task.Task_Assigned_Employee_ID).FirstOrDefault().Name</div> </div> } }
using DevExtreme.MVC.Demos.Models.SampleData; using DevExtreme.MVC.Demos.ViewModels; using System; using System.Collections.Generic; using System.Linq; using System.Web.Mvc; namespace DevExtreme.MVC.Demos.Controllers { public class SortableController : Controller { public ActionResult Kanban() { return View(new KanbanViewModel { Tasks = SampleData.EmployeeTasks, Statuses = new string[] { "Not Started", "Need Assistance", "In Progress", "Deferred", "Completed" }, Employees = SampleData.TaskEmployees }); } } }
#kanban { white-space: nowrap; } .list { border-radius: 8px; margin: 5px; background-color: rgba(192, 192, 192, 0.4); display: inline-block; vertical-align: top; white-space: normal; } .list-title { font-size: 16px; padding: 10px; padding-left: 30px; margin-bottom: -10px; font-weight: bold; } .scrollable-list { height: 400px; width: 260px; } .sortable-cards { min-height: 380px } .card { position: relative; background-color: white; box-sizing: border-box; width: 230px; padding: 10px 20px; margin: 10px; } .card-subject { padding-bottom: 10px; } .card-assignee { opacity: 0.6; } .card-priority { position: absolute; top: 10px; bottom: 10px; left: 5px; width: 5px; border-radius: 2px; background: #86C285; } .priority-1 { background: #ADADAD; } .priority-2 { background: #86C285; } .priority-3 { background: #EDC578; } .priority-4 { background: #EF7D59; }