diff --git a/src/HtmlField.php b/src/HtmlField.php
index 72c7fbe..8c52408 100644
--- a/src/HtmlField.php
+++ b/src/HtmlField.php
@@ -242,6 +242,19 @@ function(array $matches) use ($allowedStyles) {
$value = preg_replace('/ +/', ' ', $value);
}
+ // Find any alt text element refs and swap them with ref tags
+ $value = preg_replace_callback(
+ '/(alt=)([\'"])([^\'"]*)(?:#|%%23)asset:(\d+)(?:@(\d+))?:alt\2/',
+ function($matches) {
+ [, $attr, $q, $text, $ref, $siteId] = array_pad($matches, 6, null);
+
+ $ref = "asset:$ref" . ($siteId ? "@$siteId" : '') . ':alt';
+
+ return sprintf('%s%s%s', "$attr$q{", "$ref||$text", "}$q");
+ },
+ $value
+ );
+
// Find any element URLs and swap them with ref tags
$value = preg_replace_callback(
sprintf('/(href=|src=)([\'"])([^\'"\?#]*)(\?[^\'"\?#]+)?(#[^\'"\?#]+)?(?:#|%%23)([\w\\\\]+)\:(\d+)(?:@(\d+))?(\:(?:transform\:)?%s)?\2/', HandleValidator::$handlePattern),
@@ -422,6 +435,24 @@ private function _parseRefs(string $value, ?ElementInterface $element = null): s
$elementsService = Craft::$app->getElements();
+ // Parse alt attribute asset ref tags: {asset:123:alt||fallback text}
+ $value = preg_replace_callback(
+ '/(alt=)([\'"])(\{asset:(\d+(?:@\d+)?):alt(?:\|\|[^\}]+)?\})\2/',
+ function($matches) use ($element) {
+ [$fullMatch, $attr, $q, $refTag, $ref] = $matches;
+ $parsed = Craft::$app->getElements()->parseRefs($refTag, $element->siteId ?? null);
+
+ // If the ref tag couldn't be resolved, leave it alone
+ if ($parsed === $refTag) {
+ return $fullMatch;
+ }
+
+ // Output: alt="[resolved text]#asset:123:alt"
+ return $attr . $q . $parsed . '#asset:' . $ref . ':alt' . $q;
+ },
+ $value
+ );
+
return preg_replace_callback(
sprintf('/(href=|src=)([\'"])(\{([\w\\\\]+)(\:\d+(?:@\d+)?\:(?:transform\:)?%s)(?:\|\|[^\}]+)?\})(?:\?([^\'"#]*))?(#[^\'"#]+)?\2/', HandleValidator::$handlePattern),
function($matches) use ($element, $elementsService) {