Motion for Blazor,
written in C#.
Springs, gestures, keyframes, variants, drag, layout and exit animations, inspired by Framer Motion and rebuilt for Blazor. All of the maths runs in C#, none of the JavaScript wiring is yours, and no animation library ships alongside it.
dotnet add package Bit.Bmotion
<Bmotion Initial="Bm.To(opacity: 0, y: 26, scale: 0.9)" Animate="Bm.To(opacity: 1, y: 0, scale: 1)" WhileHover="Bm.To(scale: 1.05, y: -6)" WhileTap="Bm.To(scale: 0.96)" Transition="Bm.Spring(stiffness: 220, damping: 20)"> <a class="tile" href="springs">Springs</a> </Bmotion>
Capabilities
What you can build with it
Every card links to the demo that proves it, and every demo ships its own source one click away.
Springs, tweens and inertia
Stiffness and damping, or bounce and duration if that is how you think - plus the full easings.net family, per property if you want.
Springs →Gestures
WhileHover, WhileTap and WhileFocus overlay a state on the base animation and revert themselves. Tap is keyboard-accessible out of the box.
Gestures →Variants
Name your states once, then switch a whole subtree to one of them and stagger the children into place - even from a per-element function.
Variants →Keyframes
Sequences of values with their own offsets, per-segment easing and repeat behaviour, written as plain collection expressions.
Keyframes →Split text
Headlines that assemble a character, a word or a line at a time - split in C#, so nothing re-splits on re-render and a screen reader still reads the sentence.
Split text →AnimatePresence
Exit animations that run before the element actually leaves the DOM - for one element, a keyed list, or content being replaced.
AnimatePresence →Drag and reorder
Axis locks, container constraints, elastic edges, momentum - and lists that reorder themselves under the pointer without re-rendering.
Drag →Layout animations
FLIP the gap between two layouts, with border-radius correction and child counter-scaling handled for you.
Layout →Scroll and viewport
Hand a scroll-linked animation to the browser's native scroll timelines - no handler, no interop - or scrub it yourself as a motion value, or trigger it the first time an element comes into view.
Scroll →Programmatic control
Animate by selector, interpolate a bare number, build a timeline with overlapping steps, then pause it and change its speed.
Programmatic →SVG and motion paths
Send an element along a path, draw a stroke on with pathLength, or morph one shape into another.
Motion path →Accessibility and diagnostics
prefers-reduced-motion that softens rather than deletes, keyboard-accessible taps, and an inspector that shows what the engine is doing.
Accessibility →In practice
See it in code
One component, two states
Initial is where the element starts, Animate is where it is going.
Change Animate in your own state and the element animates there from wherever
it currently is - there is nothing to start or stop.
<Bmotion Initial="Bm.To(opacity: 0, y: 20)" Animate="@(_open ? Bm.To(opacity: 1, y: 0) : Bm.To(opacity: 0, y: 20))" Transition="Bm.Spring(bounce: 0.4, duration: 0.6)"> <div>Hello, Bmotion!</div> </Bmotion>
Name the states, stagger the children
Variants are named states declared once. A container switches its whole subtree to one of
them, and its transition's staggerChildren brings the children in one after
another.
<Bmotion Variants="_list" InitialState="hidden" State='@(_open ? "visible" : "hidden")' Transition="Bm.Tween(staggerChildren: 0.08, delayChildren: 0.2)"> <ul> <Bmotion Variants="_item"><li>Item 1</li></Bmotion> <Bmotion Variants="_item"><li>Item 2</li></Bmotion> </ul> </Bmotion>
Animate out before Blazor removes it
An element that has left the DOM cannot animate. BmotionAnimatePresence keeps
removed content rendered until its Exit has played - you still just flip a bool.
<BmotionAnimatePresence IsPresent="@_show" Mode="BmPresenceMode.Wait"> <Bmotion Initial="Bm.To(opacity: 0)" Animate="Bm.To(opacity: 1)" Exit="Bm.To(opacity: 0)"> <div>I animate in and out!</div> </Bmotion> </BmotionAnimatePresence>
Comparison
Why not wrap a JavaScript animation library?
A wrapper drives the DOM from a second engine behind Blazor's back, and every value it needs has to cross the interop boundary. Bmotion keeps the engine in C#, next to the state it animates.
| Concern | JavaScript library + interop | Bmotion |
|---|---|---|
| Where the maths runs | In the browser's JavaScript engine | In C# - springs, tweens, inertia, easing, colours and transforms |
| What you write | Element ids, option objects and interop glue | Razor parameters: Initial, Animate, WhileHover, Exit... |
| Exit animations | Hand-timed removal after the animation ends | Presence components hold the element until its exit has played |
| Cheap animations | Up to the library | Pre-sampled in C# and handed to the Web Animations API - no per-frame interop |
| Prerendering | Nothing moves until the script runs | BmPrerenderMode.Animate plays enter animations in CSS from the served HTML |
| Script to ship | The library plus its wrapper | One small module, imported on demand |
Where to start
Choose your path
New to Bmotion?
Install the package, register one service and animate your first element in five minutes.
Getting started →Want to see it move?
A page of live samples for every feature - hover, press, drag and scroll them, each with its source.
Open the demos →Building with an AI agent?
This site is an MCP server: point your agent at /mcp and it measures a spring on the real engine instead of guessing.
Questions
Frequently asked
Is this Framer Motion running through JavaScript interop?
No. It is inspired by Motion (Framer Motion) and keeps its vocabulary, but the engine - springs, tweens, inertia, keyframes, easing, colour interpolation, gesture state and transform composition - is C#. JavaScript is used only as a thin bridge to browser APIs, and it imports itself the first time an animation runs.
Which render modes does it work in?
Blazor WebAssembly is fully supported. On Blazor Server the compositor path works, so enter, exit, hover, tap and variant animations on transform and opacity play normally; features that need the per-frame loop - inertia, colour and dimension interpolation - become instant changes. It targets .NET 8, 9 and 10.
What happens while the page is still prerendered?
By default an element is served at its Initial state and animates once the runtime is
interactive. BmPrerenderMode.Final serves it at rest, and BmPrerenderMode.Animate
- what this site uses - plays the enter animation in pure CSS straight from the served HTML.
Does it respect prefers-reduced-motion?
Yes, by the policy you choose at registration. With BmReducedMotionMode.User transforms,
layout and dimension changes snap while opacity and colour still animate - softer than switching
everything off. <BmotionConfig ReduceMotion="true"> forces it for a subtree.
Start animating
One package, one service - and every element on the page can move.
dotnet add package Bit.Bmotion