Skip to main content

Composition animations

Composition animations are a code-driven animation system that runs directly on the render thread. They provide fine-grained control over visual properties and deliver smooth, high-performance animations without blocking the UI thread.

This API is similar to the UWP/WinUI Composition layer. Use it when you need programmatic control over animations, want render-thread performance, or need to animate properties that XAML keyframe animations do not support.

When to use composition animations

Defined inXAMLXAMLC# code
Triggered byStyle selectorsProperty value changesStartAnimation() or implicit property changes
Runs onUI threadUI threadRender thread
Best forMulti-step style-driven animationsSmooth feedback on property changesPerformance-sensitive or programmatic animations

Choose composition animations when you need to:

  • Animate visuals from code (e.g., in response to scroll position, gestures, or data changes)
  • Run animations on the render thread for maximum smoothness
  • Use expression-based or physics-based animation logic

For style-driven scenarios, Keyframe Animations and Control Transitions are simpler and more appropriate.

Core concepts

CompositionVisual and Compositor

Every Avalonia control has a corresponding CompositionVisual on the render thread. You obtain it with ElementComposition.GetElementVisual():

var visual = ElementComposition.GetElementVisual(myControl);

The Compositor is the factory object that creates animations and animation collections. Access it from any CompositionVisual:

var compositor = visual.Compositor;

All animation objects must be created through the Compositor associated with the target visual.

Animatable Properties

The following properties on CompositionVisual can be animated:

PropertyTypeDescription
OffsetVector3DThe X, Y, Z position offset of the visual.
OpacityfloatThe opacity of the visual (0.0 to 1.0).
SizeVectorThe width and height of the visual.

Explicit animations

Explicit animations run when you call StartAnimation() on a visual. You define keyframes, set a duration, and start the animation manually.

Slide-in example

This example slides a control in from the left over 400 milliseconds:

var visual = ElementComposition.GetElementVisual(myControl);
var compositor = visual.Compositor;

var animation = compositor.CreateVector3KeyFrameAnimation();
animation.Duration = TimeSpan.FromMilliseconds(400);
animation.InsertKeyFrame(0f, new Vector3D(-200, 0, 0));
animation.InsertKeyFrame(1f, new Vector3D(0, 0, 0));

visual.StartAnimation("Offset", animation);

Keyframe progress values range from 0f (start) to 1f (end). You can insert intermediate keyframes at any value between 0 and 1 for multi-step animations.

Fade-in example

var visual = ElementComposition.GetElementVisual(myControl);
var compositor = visual.Compositor;

var animation = compositor.CreateScalarKeyFrameAnimation();
animation.Duration = TimeSpan.FromMilliseconds(300);
animation.InsertKeyFrame(0f, 0f);
animation.InsertKeyFrame(1f, 1f);

visual.StartAnimation("Opacity", animation);

Implicit animations

Implicit animations trigger automatically whenever a mapped property changes. Instead of calling StartAnimation(), you assign an ImplicitAnimationCollection to the visual. Any time one of the mapped properties changes, the corresponding animation runs.

Smooth repositioning example

This example smoothly animates a control's position whenever its Offset changes:

var visual = ElementComposition.GetElementVisual(myControl);
var compositor = visual.Compositor;

var offsetAnimation = compositor.CreateVector3KeyFrameAnimation();
offsetAnimation.Duration = TimeSpan.FromMilliseconds(300);
offsetAnimation.Target = "Offset";
offsetAnimation.InsertExpressionKeyFrame(1f, "this.FinalValue");

var implicitAnimations = compositor.CreateImplicitAnimationCollection();
implicitAnimations["Offset"] = offsetAnimation;

visual.ImplicitAnimations = implicitAnimations;

The expression keyframe "this.FinalValue" tells the animation to interpolate from the current value to whatever new value the property was set to. This makes the animation reusable regardless of the specific start and end positions.

You can map multiple properties in the same collection:

var opacityAnimation = compositor.CreateScalarKeyFrameAnimation();
opacityAnimation.Duration = TimeSpan.FromMilliseconds(200);
opacityAnimation.Target = "Opacity";
opacityAnimation.InsertExpressionKeyFrame(1f, "this.FinalValue");

implicitAnimations["Opacity"] = opacityAnimation;

Integrating with XAML via attached properties

To use composition animations declaratively, wrap the setup logic in an attached property. This lets you apply composition behavior from XAML styles.

Attached property

public class CompositionAnimationHelper : AvaloniaObject
{
public static readonly AttachedProperty<bool> SmoothOffsetProperty =
AvaloniaProperty.RegisterAttached<CompositionAnimationHelper, Visual, bool>(
"SmoothOffset");

public static bool GetSmoothOffset(Visual element) =>
element.GetValue(SmoothOffsetProperty);

public static void SetSmoothOffset(Visual element, bool value) =>
element.SetValue(SmoothOffsetProperty, value);

static CompositionAnimationHelper()
{
SmoothOffsetProperty.Changed.AddClassHandler<Visual>((element, args) =>
{
if (args.NewValue is true)
{
element.AttachedToVisualTree += (_, _) =>
{
var visual = ElementComposition.GetElementVisual(element);
if (visual == null) return;
var compositor = visual.Compositor;

var animation = compositor.CreateVector3KeyFrameAnimation();
animation.Duration = TimeSpan.FromMilliseconds(300);
animation.Target = "Offset";
animation.InsertExpressionKeyFrame(1f, "this.FinalValue");

var implicit = compositor.CreateImplicitAnimationCollection();
implicit["Offset"] = animation;
visual.ImplicitAnimations = implicit;
};
}
});
}
}

XAML usage

<Style Selector="ListBoxItem">
<Setter Property="local:CompositionAnimationHelper.SmoothOffset" Value="True" />
</Style>

Every ListBoxItem now smoothly animates to its new position whenever the list reorders or items are added and removed.

API reference

Type / MemberDescription
ElementComposition.GetElementVisual(Visual)Returns the CompositionVisual for a control.
CompositionVisualRepresents a control's visual on the render thread.
CompositorFactory for creating animation and collection objects.
CreateScalarKeyFrameAnimation()Creates an animation for float properties (e.g., Opacity).
CreateVector3KeyFrameAnimation()Creates an animation for Vector3D properties (e.g., Offset).
InsertKeyFrame(float progress, T value)Adds a keyframe at the given progress (0.0 to 1.0).
InsertExpressionKeyFrame(float progress, string expression)Adds an expression-based keyframe (e.g., "this.FinalValue").
StartAnimation(string property, CompositionAnimation animation)Starts an explicit animation on the named property.
ImplicitAnimationCollectionMaps property names to animations that run automatically on change.
CompositionVisual.ImplicitAnimationsGets or sets the implicit animation collection for a visual.

See also