ngx-dnd: drag and drop in Angular when the containers nest
🕶 Drag, Drop and Sorting Library for Angular2 and beyond!
At a glance
- What is it?
- ngx-dnd is an Angular drag and drop library whose reason to exist is nested containers, since the Angular CDK directives are fine until you need a list that contains lists, and it offers both a directive API and a component API for the data driven case.
- Who is it for?
- ngx-dnd fits an Angular team that needs drag and drop where the drop targets are themselves drop targets, since that nesting case is what the CDK directives do not cover and what the library was built for.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 86 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The stated reason it exists, and the one the CDK covers
The project is explicit about its niche, which is unusual and useful. The drag-and-drop directives in the Angular CDK are described as great, and the instruction is to use that if you do not need nested DnD containers. The project says it is investigating using the CDK directives internally. So the value proposition is narrow and clear: if your drop targets can contain other drop targets, this library is for you, and if they cannot, the framework's own directives are the better answer. The feature list is the standard set for such a library: drag and drop, sorting, events for drag, drop, over and out, nesting, touch support and templating.
Installing it, and the styles question
The package is published on npm under the scoped name, and the install brings two dependencies rather than one: the library, the dragula package and the dragula type definitions, installed with npm i @swimlane/ngx-dnd @swimlane/dragula @types/dragula and saved. The dragula package and its type definitions come along because they are what the library is built on. After the install you add NgxDnDModule.forRoot() to your application module. The next step is the one that catches people out. If you are using the directives you will need to bring your own styles or include the library's release stylesheet from the release directory. There is also a polyfills change that may be needed, adding a global to the window in the polyfills file.
if (typeof window['global'] === 'undefined') {
window['global'] = window;
}That third step is a leftover from the era when bundlers expected a global object, and it is the kind of detail that tells you how the library's peer expectations have drifted over its life.
The directive API and how drop zones work
The base directives are ngxDroppable on a container and ngxDraggable on the items inside it. By default all children of a droppable element may be dragged and dropped, and adding the draggable directive to an item restricts dragging and dropping to its parent container. The documentation advises preferring the base directives to the helper components that come later. Giving multiple containers the same dropZone name allows drag and drop between those containers, and a draggable item can be restricted to specific containers by binding its directive to a list of zone names.
<div class="ngx-dnd-container" ngxDroppable="example">
<div class="ngx-dnd-item" ngxDraggable>Item 1a</div>
<div class="ngx-dnd-item" ngxDraggable>Item 2a</div>
<div class="ngx-dnd-item" ngxDraggable>Item 3a</div>
</div>
<div class="ngx-dnd-container" ngxDroppable="example">
<div class="ngx-dnd-item" ngxDraggable>Item 1b</div>
<div class="ngx-dnd-item" ngxDraggable>Item 2b</div>
<div class="ngx-dnd-item" ngxDraggable>Item 3b</div>
</div>The drop zone is a string on the directive, and it is what makes two separate containers into one logical target, which is how you move an item between lists rather than just reordering within one.
The component API, for lists you generate from data
The components encapsulate the directives and add capability for data driven structures, and the documentation says to prefer the directives to the components in general. The component takes a model, which is an array of arrays, and renders the equivalent markup itself. This component is effectively equivalent to a droppable div bound to the model with a draggable div inside an ngFor over the model, so the component is a shorthand rather than a different mechanism. The model is a plain JavaScript array of arrays.
orderableLists = [
['Item 1a', 'Item 2a', 'Item 3a'],
['Item 1b', 'Item 2b', 'Item 3b']
];And the template is one element.
<ngx-dnd-container [model]="orderableLists"> </ngx-dnd-container>The practical difference is that with the component the model is the source of truth and the DOM follows it, so a reordering is a model change rather than a DOM mutation, which matters if your state lives in a store or if you need to persist the new order.
Nesting, and what the model looks like for it
Nesting is the case the library exists for, and the model for it is a tree of objects with a label and a children array, which is the shape the component consumes. The nested example gives three top-level items, two of which have three children each, and the children are themselves objects with the same label and children structure. Passing that structure to the component is what renders a list of lists, each of which can accept a drop. The nesting works at the component level, where each container is a droppable region, and it also works at the directive level, where a droppable element inside a droppable element becomes a drop target in its own right. The distinction matters when you are building a tree editor rather than a two-level board.
Building, testing and the shape of the repository
The development workflow uses the Angular CLI. You clone the repository, change into the directory, run ng build for the library and ng serve for a dev server, and browse to localhost:4200, with the app reloading when source files change. Build artefacts go into the dist directory, and a production build adds the --prod flag in the older CLI style the project documents. Unit tests run with ng test through Karma, and the older end-to-end tests run with ng e2e through Protractor. The current package manifest tells a newer story. The version is 9.0.0, the test script runs lint and then Cypress in the electron browser, and there is a separate chrome run plus a ci script that starts the storybook server on port 6006 and waits for it before running the browser tests. The repository reflects that transition, with a cypress directory and a cypress.config.ts alongside a projects/ directory for the library sources, a tools/ directory, an eslint config file and a prettier config, and a todo.md. The last push to the repository was on 2026-07-29.
Releases, security and who writes it
The changelog is managed with a tool called chg, a simple changelog and release history manager, and contributors are asked to add change notes to the HEAD (Unreleased) section of CHANGELOG.md. The release procedure is written out as a checklist, from checking out master and pulling, through optionally removing node_modules and reinstalling, running the release tests, examining the changelog to determine the next version, branching release/X.Y.Z, updating the version in package.json and the changelog, packaging, committing, tagging, pushing, publishing, and opening a pull request. The package scripts mirror that flow, with a version script that runs the changelog tool and a postversion script that sets the metadata and amends the commit. Security has its own file, SECURITY.md, at the repository root, which is where a disclosure policy belongs even when the project does not describe one in the overview. The credits section explains the origin: ngx-dnd is a Swimlane open source project, and the company describes itself as an automated cyber security operations and incident response platform, with the stated reason for sharing the library being that they build it for their own application and like giving back to the open source community.
Editorial conclusion
ngx-dnd fits an Angular team that needs drag and drop where the drop targets are themselves drop targets, since that nesting case is what the CDK directives do not cover and what the library was built for. It does not fit a team that has no nested lists, because the documentation itself recommends the Angular CDK directives in that case, and it does not fit a team on a current Angular release expecting a modern package, since the version in the manifest is 9.0.0 and the tooling described in the project is the older Angular CLI layout. Before you adopt it, read the note about the CDK directives, and if you use the directives rather than the components, budget for bringing your own styles, since the library expects you to include its release stylesheet or supply them.
Frequently asked questions
When should I use ngx-dnd instead of the Angular CDK drag and drop directives?
The project says the CDK directives are great and to use them if you do not need nested drag and drop containers. ngx-dnd exists for the case where drop targets are themselves drop targets, and it is investigating using the CDK directives internally.
How do I install ngx-dnd and what else do I need?
Run npm i @swimlane/ngx-dnd @swimlane/dragula @types/dragula --save, add NgxDnDModule.forRoot() to your application module, and if you use the directives either bring your own styles or include the library's release stylesheet. A polyfills change adding a global to the window may also be needed.
How do I drag items between two lists in ngx-dnd?
Give multiple containers the same dropZone name. A draggable item can also be restricted to specific containers by binding its directive to a list of zone names, and the component API takes an array of arrays as its model.
How are ngx-dnd tests run?
The package scripts run lint and then Cypress in the electron browser, with a separate chrome browser run, and the ci script starts the server and waits for it before running the tests. The older workflow in the documentation uses ng test through Karma for unit tests and ng e2e through Protractor for end-to-end tests.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/swimlane-ngx-dnd)Was this useful?