Library / SDK
valor-software/ng2-dragula avatar
valor-software/ng2-dragula

ng2-dragula for Angular Drag and Drop: Setup and Constraints

Simple drag and drop with dragula

1,906 stars425 forksTypeScriptMIT

At a glance

What is it?
ng2-dragula wraps the dragula library in Angular directives, module registration, and array synchronization. It fits straightforward container-based drag and drop, but its CSS, global shim, and strict model structure impose constraints.
Who is it for?
Adopt ng2-dragula when an Angular application needs dragula-style movement of direct children between named containers and can accept its CSS, global shim, and strict array layout. Do not choose it when accessibility, keyboard reordering, or arbitrary nested content must be handled through this wrapper alone.
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 6 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 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why ng2-dragula Fits Angular Container Reordering

ng2-dragula solves a narrow but common Angular problem: letting users move direct children among containers without implementing pointer tracking, drag mirrors, and drop placement manually. It is intended for application developers who already want the behavior of dragula but need an Angular package, module setup, directives, and optional synchronization between DOM movement and TypeScript arrays.

The package does not introduce a separate drag-and-drop model. Its documentation identifies it as the official Angular wrapper for dragula. That distinction matters for evaluation. The movement behavior remains tied to dragula, while ng2-dragula adds Angular-specific registration and data plumbing. Teams looking for a different interaction model, such as a form builder with nested insertion rules, may find the direct-child design too restrictive.

The basic target is a list or group of sibling containers identified by the same `dragula` value. A developer can move an item within one container or into another container carrying that value. This makes the wrapper relevant to kanban-style boards, sortable collections, assignment panels, and grouped lists where the visible items are already represented as simple children. It does not automatically define persistence, authorization, server updates, or conflict handling.

How dragula Directives Connect DOM Movement to Angular

The central mechanism is the `dragula` directive applied to a container. The README states that the directive makes a container's direct children draggable. A string value names the dragula group, and containers with the same name can exchange children. Both `dragula="VAMPIRES"` and `[dragula]="'VAMPIRES'"` are documented as equivalent forms.

For data-driven lists, `[(dragulaModel)]` connects the container to an Angular array. The README says changes are synchronized back to that array. Since version 2, the binding no longer mutates the supplied arrays directly. It shallow-clones them and emits the resulting model, which reduces direct mutation of application state but requires consumers to use two-way binding or save the values produced by the model events.

That synchronization has a strict structural contract. A model-bound container must not contain any other elements because ng2-dragula maps each DOM child's index to the corresponding item in the array. Headers, empty-state messages, buttons, or helper rows placed inside that container can break that mapping. The practical architecture is therefore a wrapper container for decoration and a dedicated inner container whose children correspond one-for-one with array entries.

The repository also exposes a `DragulaService`, including `dropModel` and `removeModel` events for saving newly produced models. These are useful when an application wants explicit event handling rather than assigning every emitted value through the shorthand binding.

Installing ng2-dragula and Registering DragulaModule

The package is distributed through npm. Install it with either npm or Yarn, depending on the package manager already used by the Angular project.

bash
npm install ng2-dragula
# or
yarn add ng2-dragula

After installation, the README requires application-level module registration through `DragulaModule.forRoot()`. Child modules, including lazy-loaded route modules, use `DragulaModule` without calling `forRoot()` again.

typescript
import { DragulaModule } from 'ng2-dragula';
@NgModule({
  imports: [
    ...,
    DragulaModule.forRoot()
  ],
})
export class AppModule { }

The setup also includes a temporary browser-global workaround in `polyfills.ts`. The assignment is required because upstream dragula still relies on `global`.

typescript
(window as any).global = window;

This is not cosmetic configuration. Without the shim, browser execution can encounter the dependency that the README explicitly identifies as unresolved in upstream dragula. Server-side rendering and non-browser test environments should be checked separately because no SSR-specific setup is documented.

A First ng2-dragula List with Array Synchronization

A first implementation can begin with an Angular list whose direct children match the bound array. This example uses the documented group name and `[(dragulaModel)]` together.

html
<ul dragula="VAMPIRES" [(dragulaModel)]="vampires">
  <li *ngFor="let vamp of vampires">
    {{ vamp.name }} likes {{ vamp.favouriteColor }}
  </li>
</ul>

The `*ngFor` block gives each array item a corresponding `li` in document order. Dragging an item changes its position, and the binding emits the reordered shallow-cloned array back to the component. To handle that result explicitly, the documented expanded syntax is:

html
<ul dragula="VAMPIRES" [dragulaModel]="vampires" (dragulaModelChange)="vampires = $event">
  <li *ngFor="let vamp of vampires">
    {{ vamp.name }} likes {{ vamp.favouriteColor }}
  </li>
</ul>

This example should display the existing names and favorite colors in a list that supports the behavior implemented by dragula. The package requires its stylesheet as well. The README recommends a customized `dragula.css` based on classes for the in-flight mirror, hidden helper element, unselectable state, and transit source. Without those styles, markup may exist without the expected visual feedback during movement.

Dragula CSS, Grouping, and the polyfills.ts Constraint

The visual layer is part of adoption, not an optional cosmetic detail. The README asks users to add `dragula.css` to the application, for example through `styles.scss`. It provides a modified stylesheet intended to include `pointer-events: none` for the mirror and fixes associated with issues 508 and 373. The documentation notes that this version is slightly better than the copy under `node_modules/dragula/dist/dragula.css`, while also allowing further local modification.

scss
.gu-mirror {
  position: fixed !important;
  margin: 0 !important;
  z-index: 9999 !important;
  opacity: 0.8;
  pointer-events: none;
}
.gu-hide {
  left: -9999px !important;
}

A production integration should account for all documented classes, including `.gu-unselectable` and `.gu-transit`, or use the repository's complete stylesheet.

Grouping is intentionally simple. Two elements with `dragula="VAMPIRES"` belong to one movement group, while `dragula="ZOMBIES"` identifies another. A component property can hold the same string when the declaration must remain consistent across templates. This works well for static labels. It offers no documented mechanism for conditional acceptance of a specific item based on its model fields, which makes it less suitable for business rules that reject every drop into a full column or permit only certain item types.

ng2-dragula Constraints Against Native Dragula

The clearest limitation is structural. A `dragulaModel` container must contain only elements corresponding to its array. Static headings, explanatory text, selection controls, and empty-state elements belong outside that container. Even a decorative child can disturb the index mapping, leading to incorrect array synchronization. This differs from markup flexibility that may be acceptable in a plain dragula integration.

The package also requires the `(window as any).global = window` polyfill and application-managed dragula CSS. Those are concrete adoption costs. The README calls the global assignment temporary, but it remains part of the documented setup while upstream dragula depends on `global`.

The real alternative is direct use of dragula. Instead of importing `DragulaModule`, configuring Angular directives, and using `[(dragulaModel)]`, an application can connect to dragula through its own service or component code. That approach avoids the wrapper's module and model-binding conventions, but the application then owns initialization, event handling, model updates, cleanup, and synchronization. The README explicitly directs users to dragula's documentation for behavior not specific to ng2-dragula.

Neither option should be selected solely on the assumption of built-in accessibility. The documentation does not describe keyboard controls, screen-reader announcements, focus management, or accessible alternatives for moving items. Those capabilities need separate verification against the actual application requirements.

Release Compatibility, Maintenance, and MIT Implications

The repository was last pushed on 2026-10-14 and released v8.0.0 on 2026-10-14. The recent release sequence also includes v7.0.0 on 2026-03-06 and v6.0.0 on 2025-08-13. Those dates indicate recent release activity, but upgrade work still requires checking compatibility rather than assuming every Angular release is covered.

There is a documentation mismatch worth resolving before adoption. The README dependency table says the current ng2-dragula version targets Angular 16.x.x. The root `package.json` identifies version 8.0.0 and lists Angular packages at 21.2.6. Based on those two repository locations, an Angular 21 application should not infer compatibility from the older README table alone. Review the published package metadata and exercise the application build during evaluation.

The project uses the MIT license. That permits use, modification, distribution, and sublicensing subject to the license conditions, including preservation of the copyright and license notice. This is a project-level observation, not legal advice. Teams should also account for dragula's own package and license terms because ng2-dragula wraps that dependency rather than replacing its behavior.

Editorial conclusion

Adopt ng2-dragula when an Angular application needs dragula-style movement of direct children between named containers and can accept its CSS, global shim, and strict array layout. Do not choose it when accessibility, keyboard reordering, or arbitrary nested content must be handled through this wrapper alone. Before adoption, verify compatibility with the application's Angular version because the README describes 16.x.x as current while the repository package lists Angular 21.2.6, and confirm that every dragulaModel container contains only items rendered from its bound array.

Frequently asked questions

How do I install and configure ng2-dragula in an Angular application?

Install `ng2-dragula`, add `DragulaModule.forRoot()` to the application module, and include dragula's CSS. The setup also requires `(window as any).global = window` in `polyfills.ts` while upstream dragula relies on `global`.

How does ng2-dragula synchronize dragged items with an Angular array?

Attach the same array to a container with `[(dragulaModel)]` and render its entries as the container's direct children. Since version 2, the binding shallow-clones arrays and emits the result rather than directly mutating the supplied array.

What can go wrong when extra elements are placed inside a dragulaModel container?

The wrapper maps each child element's index to an associated array item. Extra elements inside the container can break that mapping and produce incorrect results, so headers and helper content should be placed outside it.

What Angular version does the current ng2-dragula release target?

The README table lists 16.x.x as current, while the root `package.json` for v8.0.0 lists Angular 21.2.6. This mismatch means an adopter needs to verify the published package metadata and build behavior for the intended Angular version.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. valor-software/ng2-dragula on GitHub
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/valor-software-ng2-dragula.svg)](https://hysenlabs.com/projects/valor-software-ng2-dragula)