diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/attribute-class/with-scoped-styles-only-in-child/dynamic/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/attribute-class/with-scoped-styles-only-in-child/dynamic/expected.html
index 9627366d70..981f56e801 100644
--- a/packages/@lwc/engine-server/src/__tests__/fixtures/attribute-class/with-scoped-styles-only-in-child/dynamic/expected.html
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/attribute-class/with-scoped-styles-only-in-child/dynamic/expected.html
@@ -221,5 +221,18 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/attribute-class/with-scoped-styles-only-in-child/dynamic/modules/x/parent/parent.html b/packages/@lwc/engine-server/src/__tests__/fixtures/attribute-class/with-scoped-styles-only-in-child/dynamic/modules/x/parent/parent.html
index ceb3187e70..6589394e6a 100644
--- a/packages/@lwc/engine-server/src/__tests__/fixtures/attribute-class/with-scoped-styles-only-in-child/dynamic/modules/x/parent/parent.html
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/attribute-class/with-scoped-styles-only-in-child/dynamic/modules/x/parent/parent.html
@@ -16,4 +16,5 @@
+
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/attribute-class/with-scoped-styles-only-in-child/dynamic/modules/x/parent/parent.js b/packages/@lwc/engine-server/src/__tests__/fixtures/attribute-class/with-scoped-styles-only-in-child/dynamic/modules/x/parent/parent.js
index 879d633a22..611eb57566 100644
--- a/packages/@lwc/engine-server/src/__tests__/fixtures/attribute-class/with-scoped-styles-only-in-child/dynamic/modules/x/parent/parent.js
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/attribute-class/with-scoped-styles-only-in-child/dynamic/modules/x/parent/parent.js
@@ -21,4 +21,7 @@ export default class extends LightningElement {
isUppercase = 'FOO BaR';
isTabs = '\tfoo\t';
isNewlines = '\nfoo\n';
+ // Skipping `>` because it messes up `formatHTML()`, and the important thing is checking
+ // that we are calling `htmlEscape()` in attribute mode, so checking `<` is sufficient.
+ hasEscapableCharacters = `"'<&`;
}
diff --git a/packages/@lwc/ssr-compiler/src/__tests__/utils/expected-failures.ts b/packages/@lwc/ssr-compiler/src/__tests__/utils/expected-failures.ts
index 4c95be787f..176201c883 100644
--- a/packages/@lwc/ssr-compiler/src/__tests__/utils/expected-failures.ts
+++ b/packages/@lwc/ssr-compiler/src/__tests__/utils/expected-failures.ts
@@ -8,8 +8,6 @@
// We should slowly drive down these test failures or at least document where we expect the failures
// TODO [#4815]: enable all SSR v2 tests
export const expectedFailures = new Set([
- 'attribute-class/with-scoped-styles-only-in-child/dynamic/index.js',
- 'attribute-class/with-scoped-styles/dynamic/index.js',
'attribute-global-html/as-component-prop/undeclared/index.js',
'attribute-global-html/as-component-prop/without-@api/index.js',
'exports/component-as-default/index.js',
diff --git a/packages/@lwc/ssr-compiler/src/compile-template/transformers/element.ts b/packages/@lwc/ssr-compiler/src/compile-template/transformers/element.ts
index 84f8f8dfba..66341e2355 100644
--- a/packages/@lwc/ssr-compiler/src/compile-template/transformers/element.ts
+++ b/packages/@lwc/ssr-compiler/src/compile-template/transformers/element.ts
@@ -81,9 +81,17 @@ const bYieldClassDynamicValue = esTemplateWithYield`
const attrValue = normalizeClass(${/* attribute value expression */ is.expression});
const shouldRenderScopeToken = hasScopedStylesheets || hasScopedStaticStylesheets(Cmp);
+ // Concatenate the scope token with the class attribute value as necessary.
+ // If either is missing, render the other alone.
+ let combinedValue = shouldRenderScopeToken ? stylesheetScopeToken : '';
if (attrValue) {
- const prefix = shouldRenderScopeToken ? stylesheetScopeToken + ' ' : '';
- yield \` class="\${prefix}\${htmlEscape(String(attrValue), true)}"\`;
+ if (combinedValue) {
+ combinedValue += ' ';
+ }
+ combinedValue += htmlEscape(String(attrValue), true);
+ }
+ if (combinedValue) {
+ yield \` class="\${combinedValue}"\`;
}
}
`;