diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index d812818ed8..fa4fd7dd07 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -56,6 +56,7 @@
+
diff --git a/samples/ControlCatalog/Pages/RelativePanelPage.axaml b/samples/ControlCatalog/Pages/RelativePanelPage.axaml
new file mode 100644
index 0000000000..3657d52bd9
--- /dev/null
+++ b/samples/ControlCatalog/Pages/RelativePanelPage.axaml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/Pages/RelativePanelPage.axaml.cs b/samples/ControlCatalog/Pages/RelativePanelPage.axaml.cs
new file mode 100644
index 0000000000..11d0a5152e
--- /dev/null
+++ b/samples/ControlCatalog/Pages/RelativePanelPage.axaml.cs
@@ -0,0 +1,19 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+ public class RelativePanelPage : UserControl
+ {
+ public RelativePanelPage()
+ {
+ this.InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/src/Avalonia.Controls/RelativePanel.AttachedProperties.cs b/src/Avalonia.Controls/RelativePanel.AttachedProperties.cs
new file mode 100644
index 0000000000..f93de5ca15
--- /dev/null
+++ b/src/Avalonia.Controls/RelativePanel.AttachedProperties.cs
@@ -0,0 +1,546 @@
+using Avalonia.Layout;
+
+#nullable enable
+
+namespace Avalonia.Controls
+{
+ public partial class RelativePanel
+ {
+ private static void OnAlignPropertiesChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
+ {
+ if (d is Layoutable layoutable && layoutable.Parent is Layoutable layoutableParent)
+ {
+ layoutableParent.InvalidateArrange();
+ }
+ }
+
+ static RelativePanel()
+ {
+ ClipToBoundsProperty.OverrideDefaultValue(true);
+
+ AboveProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ AlignBottomWithPanelProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ AlignBottomWithProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ AlignHorizontalCenterWithPanelProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ AlignHorizontalCenterWithProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ AlignLeftWithPanelProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ AlignLeftWithProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ AlignRightWithPanelProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ AlignRightWithProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ AlignTopWithPanelProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ AlignTopWithProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ AlignVerticalCenterWithPanelProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ AlignVerticalCenterWithProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ BelowProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ LeftOfProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ LeftOfProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ }
+
+ ///
+ /// Gets the value of the RelativePanel.Above XAML attached property for the target element.
+ ///
+ /// The object from which the property value is read.
+ ///
+ /// The RelativePanel.Above XAML attached property value of the specified object.
+ /// (The element to position this element above.)
+ ///
+ [ResolveByName]
+ public static object GetAbove(AvaloniaObject obj)
+ {
+ return (object)obj.GetValue(AboveProperty);
+ }
+
+ ///
+ /// Sets the value of the RelativePanel.Above XAML attached property for a target element.
+ ///
+ /// The object to which the property value is written.
+ /// The value to set. (The element to position this element above.)
+ public static void SetAbove(AvaloniaObject obj, object value)
+ {
+ obj.SetValue(AboveProperty, value);
+ }
+
+
+ ///
+ /// Identifies the XAML attached property.
+ ///
+
+ public static readonly AttachedProperty