diff --git a/src/Connected.Components/Components/TransitionAnimator.razor b/src/Connected.Components/Components/TransitionAnimator.razor
new file mode 100644
index 0000000..399cfd1
--- /dev/null
+++ b/src/Connected.Components/Components/TransitionAnimator.razor
@@ -0,0 +1,107 @@
+@using Connected.Utilities;
+
+
+ @if (ContentVisible)
+ {
+ @ChildContent
+ }
+
+
+
+
+@code {
+ private bool _visible = false;
+
+ ///
+ /// The class to append to the container while content is visible and transitioning in
+ ///
+ [Parameter, EditorRequired]
+ public string? TransitionInClass { get; set; }
+
+ ///
+ /// The class to append to the container while content is transitioning out and hidden
+ ///
+ [Parameter, EditorRequired]
+ public string? TransitionOutClass { get; set; }
+
+ ///
+ /// The class to append to the container to control transitions
+ ///
+ [Parameter]
+ public string? TransitionContainerClass { get; set; } = "transition-container-component";
+
+ ///
+ /// Controls the visibility of the child content
+ ///
+ [Parameter, EditorRequired]
+ public bool Visible { get => _visible; set => StartTransition(value); }
+
+ ///
+ /// The content to show/hide
+ ///
+ [Parameter, EditorRequired]
+ public RenderFragment? ChildContent { get; set; }
+
+ ///
+ /// Indicates a transition has ended. Useful for visual cleanup.
+ ///
+ [Parameter]
+ public EventCallback TransitionEnded { get; set; }
+
+ ///
+ /// The duration of transitions in milliseconds.
+ ///
+ [Parameter]
+ public int TransitionDuration { get; set; } = 2000;
+
+ private bool TransitioningIn { get; set; }
+
+ private bool TransitioningOut { get; set; }
+
+ private bool ContentVisible { get; set; }
+
+ private CssBuilder ClassList
+ {
+ get
+ {
+ return new CssBuilder(TransitionContainerClass)
+ .AddClass(TransitionInClass, TransitioningIn)
+ .AddClass(TransitionOutClass, TransitioningOut);
+ }
+ }
+
+ private void StartTransition(bool visible)
+ {
+ if (visible == Visible)
+ return;
+
+ _visible = visible;
+
+ TransitioningIn = visible;
+
+ TransitioningOut = !visible;
+
+ if (visible)
+ ContentVisible = true;
+
+ StateHasChanged();
+ }
+
+ private void TransitionEnd()
+ {
+ ContentVisible = Visible;
+ StateHasChanged();
+
+ TransitionEnded.InvokeAsync();
+ }
+
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+ ContentVisible = Visible;
+ }
+}