diff --git a/apps/oxfmt/conformance/run.ts b/apps/oxfmt/conformance/run.ts
index bc1ae5d7ba617..d73a93dd2af66 100644
--- a/apps/oxfmt/conformance/run.ts
+++ b/apps/oxfmt/conformance/run.ts
@@ -95,8 +95,7 @@ const categories: Category[] = [
],
optionSets: [{ printWidth: 80 }],
notes: {
- "comment-inside.js":
- "html embed expressions not yet implemented; css `${}` indentation bug (TODO)",
+ "comment-inside.js": "html embed expressions not yet implemented",
},
},
];
diff --git a/apps/oxfmt/conformance/snapshots/conformance.snap.md b/apps/oxfmt/conformance/snapshots/conformance.snap.md
index 6abd6b80cdbd3..598710e1f4098 100644
--- a/apps/oxfmt/conformance/snapshots/conformance.snap.md
+++ b/apps/oxfmt/conformance/snapshots/conformance.snap.md
@@ -68,4 +68,4 @@
| File | Note |
| :--- | :--- |
-| [comment-inside.js](diffs/xxx-in-js-comment/comment-inside.js.md) | html embed expressions not yet implemented; css `${}` indentation bug (TODO) |
+| [comment-inside.js](diffs/xxx-in-js-comment/comment-inside.js.md) | html embed expressions not yet implemented |
diff --git a/apps/oxfmt/conformance/snapshots/diffs/xxx-in-js-comment/comment-inside.js.md b/apps/oxfmt/conformance/snapshots/diffs/xxx-in-js-comment/comment-inside.js.md
index 818b5358b3535..96b466aebaeb6 100644
--- a/apps/oxfmt/conformance/snapshots/diffs/xxx-in-js-comment/comment-inside.js.md
+++ b/apps/oxfmt/conformance/snapshots/diffs/xxx-in-js-comment/comment-inside.js.md
@@ -1,6 +1,6 @@
# comment-inside.js
-> html embed expressions not yet implemented; css `${}` indentation bug (TODO)
+> html embed expressions not yet implemented
## Option 1
@@ -31,29 +31,7 @@
graphql`
${
-@@ -32,17 +32,15 @@
- }
- `;
-
- css`
-- ${
-- foo
-- /* comment */
-+ ${foo
-+ /* comment */
- }
- `;
- css`
-- ${
-- foo
-- /* comment */
-+ ${foo
-+ /* comment */
- }
- `;
-
- markdown`${
-@@ -61,7 +59,6 @@
+@@ -61,7 +61,6 @@
${x(
foo, // fg
@@ -103,13 +81,15 @@ graphql`
`;
css`
- ${foo
- /* comment */
+ ${
+ foo
+ /* comment */
}
`;
css`
- ${foo
- /* comment */
+ ${
+ foo
+ /* comment */
}
`;
diff --git a/crates/oxc_formatter/src/print/template/embed/css.rs b/crates/oxc_formatter/src/print/template/embed/css.rs
index 47b29881da274..f8c7919f0868f 100644
--- a/crates/oxc_formatter/src/print/template/embed/css.rs
+++ b/crates/oxc_formatter/src/print/template/embed/css.rs
@@ -1,5 +1,6 @@
use oxc_allocator::{Allocator, StringBuilder};
use oxc_ast::ast::*;
+use oxc_span::GetSpan;
use crate::{
IndentWidth,
@@ -102,19 +103,40 @@ pub(super) fn format_css_doc<'a>(
write_text_with_line_breaks(f, part, allocator, indent_width);
}
} else if let Some(idx) = part.parse::().ok()
- && let Some(expr) = expressions.get(idx)
+ && let Some(&expr) = expressions.get(idx)
{
- // Format `${expr}` directly to preserve soft line breaks
- // so the printer can decide line breaks based on `printWidth`.
- // (Regular template expressions use `RemoveSoftLinesBuffer`
- // which forces single-line layout.)
- // TODO: Expression indentation is incorrect — Prettier indents
- // `${ expr }` with the surrounding CSS block, but we don't.
- // See `multiparser-comments/comment-inside.js` css cases.
- write!(
- f,
- [group(&format_args!("${", expr, line_suffix_boundary(), "}"))]
- );
+ // Prettier's `printTemplateExpression()` adds indent+softline when:
+ // - the original source has newlines in the interpolation
+ // - AND the expression is a comment-bearing node or Identifier/etc
+ // For CSS embed, the relevant case is comments inside `${...}`.
+ let has_newline = f.source_text().has_newline_before(expr.span().start)
+ || f.source_text().has_newline_after(expr.span().end);
+ let has_comment = has_newline && {
+ let comments = f.context().comments();
+ let leading = comments.comments_before(expr.span().start);
+ let trailing =
+ comments.comments_before_character(expr.span().start, b'}');
+ !leading.is_empty() || !trailing.is_empty()
+ };
+
+ let format_expr = format_with(|f| {
+ if has_comment {
+ write!(
+ f,
+ [
+ indent(&format_args!(
+ soft_line_break(),
+ expr,
+ line_suffix_boundary()
+ )),
+ soft_line_break()
+ ]
+ );
+ } else {
+ write!(f, [expr, line_suffix_boundary()]);
+ }
+ });
+ write!(f, [group(&format_args!("${", format_expr, "}"))]);
}
}
}