diff --git a/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorRuntimeNodeWriter.cs b/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorRuntimeNodeWriter.cs
index b1de0647cd..4dcae0feba 100644
--- a/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorRuntimeNodeWriter.cs
+++ b/src/Microsoft.AspNetCore.Blazor.Razor.Extensions/BlazorRuntimeNodeWriter.cs
@@ -543,6 +543,15 @@ namespace Microsoft.AspNetCore.Blazor.Razor
public override void BeginWriteAttribute(CodeWriter codeWriter, string key)
{
+ // Temporary workaround for https://github.com/aspnet/Blazor/issues/219
+ // Remove this logic once the underlying HTML parsing issue is fixed,
+ // as we don't really want special cases like this.
+ const string dataUnderscore = "data_";
+ if (key.StartsWith(dataUnderscore, StringComparison.Ordinal))
+ {
+ key = "data-" + key.Substring(dataUnderscore.Length);
+ }
+
codeWriter
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(BlazorApi.RenderTreeBuilder.AddAttribute)}")
.Write((_sourceSequence++).ToString())
diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/RenderingRazorIntegrationTest.cs b/test/Microsoft.AspNetCore.Blazor.Build.Test/RenderingRazorIntegrationTest.cs
index 942d83e312..c0c6b1b263 100644
--- a/test/Microsoft.AspNetCore.Blazor.Build.Test/RenderingRazorIntegrationTest.cs
+++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/RenderingRazorIntegrationTest.cs
@@ -180,6 +180,79 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
frame => AssertFrame.Attribute(frame, "attr", "Hello, WORLD with number 246!", 1));
}
+ [Fact]
+ public void SupportsHyphenedAttributesWithCSharpExpressionValues()
+ {
+ // Arrange/Act
+ var component = CompileToComponent(
+ "@{ var myValue = \"My string\"; }"
+ + "");
+
+ // Assert
+ Assert.Collection(GetRenderTree(component),
+ frame => AssertFrame.Element(frame, "elem", 2, 0),
+ frame => AssertFrame.Attribute(frame, "abc-def", "My string", 1));
+ }
+
+ [Fact]
+ public void SupportsDataDashAttributesWithLiteralValues()
+ {
+ // Arrange/Act
+ var component = CompileToComponent(
+ "");
+
+ // Assert
+ Assert.Collection(GetRenderTree(component),
+ frame => AssertFrame.Element(frame, "elem", 2, 0),
+ frame => AssertFrame.Attribute(frame, "data-abc", "Hello", 1));
+ }
+
+ [Fact(Skip = "Currently broken due to #219. TODO: Once the issue is fixed, re-enable this test, remove the test below, and remove the implementation of its workaround.")]
+ public void SupportsDataDashAttributesWithCSharpExpressionValues()
+ {
+ // Arrange/Act
+ var component = CompileToComponent(
+ "@{ var myValue = \"My string\"; }"
+ + "");
+
+ // Assert
+ Assert.Collection(GetRenderTree(component),
+ frame => AssertFrame.Element(frame, "elem", 2, 0),
+ frame => AssertFrame.Attribute(frame, "data-abc", "My string", 1));
+ }
+
+ [Fact]
+ public void TemporaryWorkaround_ConvertsDataUnderscoreAttributesToDataDash()
+ {
+ // This is a temporary workaround for https://github.com/aspnet/Blazor/issues/219
+ //
+ // Currently Razor's HtmlMarkupParser looks for data-* attributes and handles
+ // them differently: https://github.com/aspnet/Razor/blob/dev/src/Microsoft.AspNetCore.Razor.Language/Legacy/HtmlMarkupParser.cs#L934
+ // This is because Razor was historically used only on the server, and there's
+ // an argument that data-* shouldn't support conditional server-side rendering
+ // because of its HTML semantics. The result is that information about data-*
+ // attributes isn't retained in the IR - all we get there is literal HTML
+ // markup, which the Blazor code writer can't do anything useful with.
+ //
+ // The real solution would be to disable the parser's "data-*" special case
+ // for Blazor. We don't yet have a mechanism for disabling it, so as a short
+ // term workaround, we support data_* as an alternative syntax that renders
+ // as data-* in the DOM.
+ //
+ // This workaround (the automatic conversion of data_* to data-*) will be removed
+ // as soon as the underlying HTML parsing issue is resolved.
+
+ // Arrange/Act
+ var component = CompileToComponent(
+ "@{ var myValue = \"My string\"; }"
+ + "");
+
+ // Assert
+ Assert.Collection(GetRenderTree(component),
+ frame => AssertFrame.Element(frame, "elem", 2, 0),
+ frame => AssertFrame.Attribute(frame, "data-abc", "My string", 1));
+ }
+
[Fact]
public void SupportsAttributesWithEventHandlerValues()
{