diff --git a/native/Avalonia.Native/src/OSX/automation.mm b/native/Avalonia.Native/src/OSX/automation.mm
index f8c288c489..b42dc22f7a 100644
--- a/native/Avalonia.Native/src/OSX/automation.mm
+++ b/native/Avalonia.Native/src/OSX/automation.mm
@@ -220,6 +220,11 @@
return GetNSStringAndRelease(_peer->GetHelpText());
}
+- (NSString *)accessibilityPlaceholderValue
+{
+ return GetNSStringAndRelease(_peer->GetPlaceholderText());
+}
+
- (id)accessibilityValue
{
if (_peer->IsRangeValueProvider())
diff --git a/samples/IntegrationTestApp/Pages/AutomationPage.axaml b/samples/IntegrationTestApp/Pages/AutomationPage.axaml
index c02bc1baa6..91317bcb11 100644
--- a/samples/IntegrationTestApp/Pages/AutomationPage.axaml
+++ b/samples/IntegrationTestApp/Pages/AutomationPage.axaml
@@ -10,7 +10,7 @@
TextBlockWithNameAndAutomationId
Label for TextBox
-
+
Foo
diff --git a/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs
index b32b60118c..47754c9b50 100644
--- a/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs
+++ b/src/Avalonia.Controls/Automation/Peers/AutomationPeer.cs
@@ -283,12 +283,29 @@ namespace Avalonia.Automation.Peers
///
public string GetHelpText() => GetHelpTextCore() ?? string.Empty;
+ ///
+ /// Gets text that provides a placeholder for the element that is associated with this automation peer.
+ ///
+ ///
+ ///
+ /// -
+ /// Windows
+ /// No mapping.
+ ///
+ /// -
+ /// macOS
+ /// NSAccessibilityProtocol.accessibilityPlaceholderValue
+ ///
+ ///
+ ///
+ public string GetPlaceholderText() => GetPlaceholderTextCore() ?? string.Empty;
+
///
/// Gets the control type for the element that is associated with the UI Automation peer.
///
///
/// Gets the type of the element.
- ///
+ ///
///
/// -
/// Windows
@@ -595,6 +612,7 @@ namespace Avalonia.Automation.Peers
protected abstract AutomationPeer? GetLabeledByCore();
protected abstract string? GetNameCore();
protected virtual string? GetHelpTextCore() => null;
+ protected virtual string? GetPlaceholderTextCore() => null;
protected virtual AutomationLandmarkType? GetLandmarkTypeCore() => null;
protected virtual int GetHeadingLevelCore() => 0;
protected virtual string? GetItemTypeCore() => null;
diff --git a/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs
index cdab4911f2..aaabc6f495 100644
--- a/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs
+++ b/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs
@@ -132,6 +132,12 @@ namespace Avalonia.Automation.Peers
result = ToolTip.GetTip(Owner) as string;
}
+ // Windows uses HelpText for placeholder text; macOS uses a separate property.
+ if (string.IsNullOrWhiteSpace(result))
+ {
+ result = GetPlaceholderTextCore();
+ }
+
return result;
}
protected override AutomationLandmarkType? GetLandmarkTypeCore() => AutomationProperties.GetLandmarkType(Owner);
diff --git a/src/Avalonia.Controls/Automation/Peers/InteropAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/InteropAutomationPeer.cs
index 5dfd507e1b..cdbb3286d8 100644
--- a/src/Avalonia.Controls/Automation/Peers/InteropAutomationPeer.cs
+++ b/src/Avalonia.Controls/Automation/Peers/InteropAutomationPeer.cs
@@ -29,6 +29,7 @@ internal class InteropAutomationPeer : AutomationPeer
protected override AutomationPeer? GetLabeledByCore() => throw new NotImplementedException();
protected override string? GetNameCore() => throw new NotImplementedException();
protected override string? GetHelpTextCore() => throw new NotImplementedException();
+ protected override string? GetPlaceholderTextCore() => throw new NotImplementedException();
protected override IReadOnlyList GetOrCreateChildrenCore() => throw new NotImplementedException();
protected override AutomationPeer? GetParentCore() => _parent;
protected override bool HasKeyboardFocusCore() => throw new NotImplementedException();
diff --git a/src/Avalonia.Controls/Automation/Peers/TextBoxAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/TextBoxAutomationPeer.cs
index dacec48d36..4f41e088c6 100644
--- a/src/Avalonia.Controls/Automation/Peers/TextBoxAutomationPeer.cs
+++ b/src/Avalonia.Controls/Automation/Peers/TextBoxAutomationPeer.cs
@@ -21,6 +21,8 @@ namespace Avalonia.Automation.Peers
return AutomationControlType.Edit;
}
+ protected override string? GetPlaceholderTextCore() => Owner.PlaceholderText;
+
protected virtual void OwnerPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if(e.Property == TextBox.TextProperty)
diff --git a/src/Avalonia.Native/AvnAutomationPeer.cs b/src/Avalonia.Native/AvnAutomationPeer.cs
index 86e0c5453d..cb418261f7 100644
--- a/src/Avalonia.Native/AvnAutomationPeer.cs
+++ b/src/Avalonia.Native/AvnAutomationPeer.cs
@@ -46,6 +46,7 @@ namespace Avalonia.Native
public IAvnAutomationPeer? LabeledBy => Wrap(_inner.GetLabeledBy());
public IAvnString? Name => _inner.GetName().ToAvnString();
public IAvnString? HelpText => _inner.GetHelpText().ToAvnString();
+ public IAvnString? PlaceholderText => _inner.GetPlaceholderText().ToAvnString();
public AvnLandmarkType LandmarkType => (AvnLandmarkType?)_inner.GetLandmarkType() ?? AvnLandmarkType.LandmarkNone;
public int HeadingLevel => _inner.GetHeadingLevel();
public IAvnAutomationPeer? Parent => Wrap(_inner.GetParent());
diff --git a/src/Avalonia.Native/avn.idl b/src/Avalonia.Native/avn.idl
index 7aabeceb72..ea8c1b4694 100644
--- a/src/Avalonia.Native/avn.idl
+++ b/src/Avalonia.Native/avn.idl
@@ -1328,6 +1328,7 @@ interface IAvnAutomationPeer : IUnknown
void ValueProvider_SetValue([const] char* value);
IAvnString* GetHelpText();
+ IAvnString* GetPlaceholderText();
AvnLandmarkType GetLandmarkType();
int GetHeadingLevel();