Skip to content

Getting started

One package and one service registration - then a BdndProvider around any interactively rendered region, with draggables and drop targets inside it. You drag data of a type, not a view, and the drag state lives in C#.

Install

In a Blazor Web App with an interactive client, the package belongs in the .Client project, next to the pages that drag.

dotnet add package Bit.Bdnd

Register the service

It registers BdndInterop, the scoped wrapper around the script module that every draggable and drop target injects. The drag-and-drop manager itself is not a service: each BdndProvider creates its own and shares it with the components inside it. In a Blazor Web App, register it in both Program.cs files - the pages are prerendered on the server before they run in the browser.

// Program.cs - in every project that renders the components
builder.Services.AddBitBdndServices();

And the namespace, in _Imports.razor:

@using Bit.Bdnd
There is no stylesheet to link and no script tag to add: the components import their module, _content/Bit.Bdnd/bit-bdnd.js, themselves the first time they need it.

A first drag and drop

Wrap the region in a BdndProvider and declare sources and targets inside it. A draggable's Type is what a target matches against its Accept list, and its Item is what the target's OnDrop receives. Each one's child content gets the collected state - IsDragging for a source, IsOver and CanDrop for a target - to render from.

<BdndProvider>
    @foreach (var name in _boxes)
    {
        <BdndDraggable TItem="string" Type="box" Item="name" Context="drag">
            <div class="box" style="opacity: @(drag.IsDragging ? 0.4 : 1)">
                @name
            </div>
        </BdndDraggable>
    }

    <BdndDropTarget TItem="string" Accept="box" OnDrop="HandleDrop" Context="drop">
        <div class="dustbin"
             style="background: @(drop.IsOver ? "#15803d" : "#1f2430")">
            @(drop.IsOver ? "Release to drop" : _label)
        </div>
    </BdndDropTarget>
</BdndProvider>

@code {
    private readonly string[] _boxes = ["Glass", "Banana", "Paper"];
    private string _label = "Drag a box here";

    private void HandleDrop(BdndDropEventArgs<string> e)
        => _label = $"Dropped: {e.Item}";
}
Live
Glass
Banana
Paper
Drag a box here
Three things make this work: the components sit inside one BdndProvider; the draggable's Type is one of the types the target lists in Accept; and the page is interactive, because a statically rendered page never wires up drag events.

Core concepts

Bdnd brings React DnD's data-driven model to Blazor as components rather than hooks.

ConceptIn Bdnd
Items and types You drag an item - any C# object - of a type, a string. A target accepts the types it lists in Accept or AcceptTypes; the item's .NET type does not take part.
Components BdndProvider, BdndDraggable, BdndDropTarget, BdndDragLayer and BdndDragHandle - React DnD's provider, useDrag, useDrop, useDragLayer and a drag handle.
Collected state What a component's child content renders from: IsDragging, IsOver, IsOverShallow, CanDrop, the item and the offsets.
Monitor IBdndMonitor, a read-only view of the live drag state, on every collected state and callback argument as Monitor.
Backend The browser's native HTML5 drag events, so files, text and links dragged in from outside the browser drop too.
An unhandled error has occurred. Reload 🗙