Lol, I have the same problem yesterday and fixed it. Decompile the "RenderVariantField" pipeline in "Sitecore.XA.Foundation.RenderingVariants.Pipelines.RenderVariantField", patch the config that the pipeline points to your implementation ("patch:instead").
There are two problems:
First Problem:
Your Link field, like the default in the Link-Component, is rendered like this (I removed the customdata-attribute...):
<div class="field-link" #DATA-ATTRIBUTE SHOULD APPEAR HERE#>
<a target="_blank" data-variantitemid="{40BCAED1-7B1F-4B00-9B68-BC26BE3094EA}" href="http://www.google.de" rel="noopener noreferrer" data-variantfieldname="Link" sc-part-of="field" class="scEnabledChrome">Link Text</a>
The data attribute is not set, because of the "RenderVariantField" pipeline. I don't know why but SXA prevents to add attributes to "images" and "general links":
protected virtual void AddWrapperDataAttributes(
Sitecore.XA.Foundation.RenderingVariants.Fields.VariantField variantField,
RenderVariantFieldArgs args,
HtmlGenericControl tag)
{
if (variantField.DataAttributes.Count <= 0)
return;
Field field = args.Item.Fields[variantField.FieldName];
string first = field != null ? field.Type : string.Empty;
if (first.Is("Image") || first.Is("General Link"))
return;
this.AddWrapperDataAttributes((RenderingVariantFieldBase) variantField, args, tag);
}
This could easily be fixed, but this leads directly to the second problem...
Second Problem:
Even if you change that behaviour, for example you want to add a style attribute like "style: color: #fff;", the styles will not be applied on the link, because the color will be overwritten by the "optimized.min.css" file and your link will still be black.
After deeper investigation I saw that the general link control is rendered in a different way and they missed to replace the tokens there. But overwriting this method was the solution for me! Original code:
protected virtual IDictionary<string, string> GetVariantAttributes(
RenderingVariantFieldBase variantField,
Item item)
{
Dictionary<string, string> dictionary = new Dictionary<string, string>();
if (variantField.DataAttributes.Count > 0)
{
foreach (string dataAttribute1 in (NameObjectCollectionBase) variantField.DataAttributes)
{
string dataAttribute2 = variantField.DataAttributes[dataAttribute1];
if (!string.IsNullOrWhiteSpace(dataAttribute2))
{
string str = this.ResolveAttributeValues(dataAttribute2, item, (object) null);
if (!string.IsNullOrWhiteSpace(str))
dictionary.Add(dataAttribute1, str);
}
}
}
return (IDictionary<string, string>) dictionary;
}
For me the code looks similar to the "AddWrapperDataAttributes"-Method, but without the part were they replace the token values. I added a new method for the "GetAttributeTokenValues"-Method which works for a "Dictionary" instead of a "AttributeCollection":
// Custom Implementation for a Dictionary
protected virtual void GetAttributeTokenValues(
Item item,
Dictionary<string, string> attributes,
MatchCollection matches,
string value,
string key)
{
foreach (Match match in matches)
{
var attributeTokenValue = GetAttributeTokenValue(match.Groups[1].Value, item);
value = value.Replace(match.Value, attributeTokenValue);
attributes.Add(key, value);
}
}
Then overwrite the "GetVariantsAttribute"-Method like this:
// Note: Override due to token customization
protected override IDictionary<string, string> GetVariantAttributes(
RenderingVariantFieldBase variantField,
Item item)
{
var dictionary = new Dictionary<string, string>();
if (variantField.DataAttributes.Count <= 0)
{
return dictionary;
}
foreach (string dataAttribute1 in variantField.DataAttributes)
{
var dataAttribute2 = variantField.DataAttributes[dataAttribute1];
if (string.IsNullOrWhiteSpace(dataAttribute2))
{
continue;
}
// Customization: We do here check for Tokens as well
var matches = AttributeFieldToken.Matches(dataAttribute2);
if (matches.Count > 0)
{
GetAttributeTokenValues(item, dictionary, matches, dataAttribute2, dataAttribute1);
}
else
{
var str = ResolveAttributeValues(dataAttribute2, item, null);
if (!string.IsNullOrWhiteSpace(str))
{
dictionary.Add(dataAttribute1, str);
}
}
}
return dictionary;
}
That works like a charm! The attributes are now added to the inner link (I removed the customdata-attribute...):
<div class="field-link">
<a target="_blank" !!! style="color: #fff;" !!! data-variantitemid="{40BCAED1-7B1F-4B00-9B68-BC26BE3094EA}" href="http://www.google.de" rel="noopener noreferrer" data-variantfieldname="Link" sc-part-of="field" class="scEnabledChrome">Link Text</a>
Give it a try! Have fun!
Best regards
Dirk