loading

Drag

Drag="true" is the entire opt-in. Everything after that is a refinement of the same gesture: which axes it may use, how far it may go, how it behaves at the edges, what happens to the momentum when you let go, and which part of the element is allowed to start it. Drag runs on the per-frame engine, so it is a Blazor WebAssembly feature; on Blazor Server the element simply does not move.

Axes and constraints

Drag="BmDrag.X" or BmDrag.Y locks the gesture to one axis, and DragConstraints bounds how far it may travel. DragElastic is what happens past that bound: 0 is a hard wall, 1 is no resistance at all, and the values in between let the element overshoot against increasing resistance and spring back on release.

Free drag · elastic 0.5
X only · constrained to ±120 px
Razor

Constrain to a container

Numeric bounds mean re-deriving them every time the layout changes. Element bounds do not: BmDragConstraints.Parent() keeps the element inside its parent and BmDragConstraints.Within(".selector") inside any container you name. Either is measured at each drag start - and re-measured live if the container resizes mid-drag - so a responsive layout needs no extra work.

Razor

Momentum and fling

A drag that stops dead where your finger lifted feels like a bug. DragMomentum (on by default) carries the release velocity into an inertia animation that decelerates on its own; DragTransition replaces the spring it settles with. DragSnapToOrigin ignores the momentum entirely and springs the element home, which is the right answer for a card you swipe to dismiss. DragDirectionLock commits to whichever axis the gesture starts on and ignores the other for the rest of it - the behaviour a scrollable list wants from a two-axis drag.

Fling it · momentum on
Snaps back to origin
Direction lock · first move wins
locked axis: none yet
Razor

Snapping on release

Momentum answers how fast the element stops; modifyTarget answers where. A DragTransition written as an inertia hands the projected resting position to your function and uses whatever comes back, which is the whole of carousel paging and grid snapping. Bm.SnapTo(step) rounds to a grid, Bm.SnapTo([…]) picks the nearest of a fixed set of stops. With one set, even a slow release still travels to the nearest stop - and the snap is applied before the constraints, so it can never land outside them.

Grid · settles every 60 px
Pages · snaps to 1 of 3
123
Razor

Handles and drag controls

Making a whole row draggable costs you every click and text selection inside it. DragHandle restricts the gesture to a grip within the element and leaves the rest alone. BmDragControls inverts the relationship: some other element starts the drag - pair it with DragListener="false" so the controls are the only trigger, and pressing anywhere on a track grabs its thumb. BmDragElastic.Edges tunes the give per edge, so a panel can be rigid where it docks and springy where it does not.

Drag me by the grip only
Rigid left/top · elastic right/bottom
Razor

Drag events

OnDragStart and OnDragEnd bracket the gesture, and OnDrag fires throughout it - enough to persist a position, mark a form dirty, or light up a drop target. For the pointer's actual coordinates and velocity, use the pan callbacks on the gestures page.

Drag the box
Razor

Nested drag and propagation

A draggable inside a draggable is ambiguous, so Bmotion resolves it the way motion.dev does: the child stops propagation and only the child moves. Set DragPropagation="true" on the child when you want the gesture to reach the parent as well and both to travel together.

child isolates (default)
child propagates
Razor
Bmotion 0 el · 0 active
An unhandled error has occurred. Reload 🗙