+ // should flow with the text and not force line breaks.
+ if !is_inline_element_from_element(&child) {
+ meta.any_tag = true;
+ }
}
AnyHtmlElement::AnyHtmlContent(AnyHtmlContent::HtmlContent(text)) => {
meta.meaningful_text = meta.meaningful_text
diff --git a/crates/biome_html_formatter/src/utils/children.rs b/crates/biome_html_formatter/src/utils/children.rs
index 41c052cd8831..3c878191fd3c 100644
--- a/crates/biome_html_formatter/src/utils/children.rs
+++ b/crates/biome_html_formatter/src/utils/children.rs
@@ -396,6 +396,31 @@ where
} else {
builder.entry(HtmlChild::NonText(child.clone()));
}
+
+ // Check for trailing whitespace, and preserve it if
+ // - its embedded expression content
+ // - its an element
+ // This preserves spaces between expressions/elements and following text content.
+ if matches!(
+ &child,
+ AnyHtmlElement::AnyHtmlContent(_)
+ | AnyHtmlElement::HtmlElement(_)
+ | AnyHtmlElement::HtmlSelfClosingElement(_)
+ ) && let Some(last_token) = child.syntax().last_token()
+ && last_token.has_trailing_whitespace()
+ {
+ // Check if trailing trivia contains a newline
+ let has_newline = last_token
+ .trailing_trivia()
+ .pieces()
+ .any(|piece| piece.is_newline());
+ if has_newline {
+ builder.entry(HtmlChild::Newline);
+ } else {
+ builder.entry(HtmlChild::Whitespace);
+ }
+ }
+
prev_child_was_content = false;
}
}
diff --git a/crates/biome_html_formatter/src/utils/metadata.rs b/crates/biome_html_formatter/src/utils/metadata.rs
index 7774fff5cdfc..f8bdf39ae74a 100644
--- a/crates/biome_html_formatter/src/utils/metadata.rs
+++ b/crates/biome_html_formatter/src/utils/metadata.rs
@@ -809,6 +809,22 @@ pub(crate) fn is_inline_element(tag_name: &HtmlTagName) -> bool {
.any(|tag| tag_name.text_trimmed().eq_ignore_ascii_case(tag))
}
+/// Checks if an element is an inline element based on its tag name.
+pub(crate) fn is_inline_element_from_element(element: &AnyHtmlElement) -> bool {
+ let name = match element {
+ AnyHtmlElement::HtmlElement(element) => {
+ element.opening_element().and_then(|element| element.name())
+ }
+ AnyHtmlElement::HtmlSelfClosingElement(element) => element.name(),
+ _ => return false,
+ };
+ let Ok(name) = name else {
+ return false;
+ };
+
+ is_inline_element(&name)
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/crates/biome_html_formatter/tests/specs/html/elements/inline/mixed-block-inline.html.snap b/crates/biome_html_formatter/tests/specs/html/elements/inline/mixed-block-inline.html.snap
index 00abe2f600b3..53621cc0a0c9 100644
--- a/crates/biome_html_formatter/tests/specs/html/elements/inline/mixed-block-inline.html.snap
+++ b/crates/biome_html_formatter/tests/specs/html/elements/inline/mixed-block-inline.html.snap
@@ -1,7 +1,6 @@
---
source: crates/biome_formatter_test/src/snapshot_builder.rs
info: elements/inline/mixed-block-inline.html
-snapshot_kind: text
---
# Input
@@ -30,11 +29,8 @@ Self close void elements: never
```html
- hello foo foo
- foo
- foo foo foo barbarbar foo
- foo foo
- foo
+ hello foo foo foo
foo foo foo
+ barbarbar foo foo foo foo
foo foo
```
diff --git a/crates/biome_html_formatter/tests/specs/html/elements/inline/tags-hug-content-longer-w-attr.html.snap b/crates/biome_html_formatter/tests/specs/html/elements/inline/tags-hug-content-longer-w-attr.html.snap
index ee6cf186292d..40f34953d7d4 100644
--- a/crates/biome_html_formatter/tests/specs/html/elements/inline/tags-hug-content-longer-w-attr.html.snap
+++ b/crates/biome_html_formatter/tests/specs/html/elements/inline/tags-hug-content-longer-w-attr.html.snap
@@ -1,7 +1,6 @@
---
source: crates/biome_formatter_test/src/snapshot_builder.rs
info: elements/inline/tags-hug-content-longer-w-attr.html
-snapshot_kind: text
---
# Input
@@ -30,7 +29,7 @@ Self close void elements: never
```html
asdfasdf foo bar things much morelonger things lorem ipsum or
+ >asdfasdf foo bar things much more longer things lorem ipsum or
something idk i put pineapple in strombolis
```
diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/each_nested.svelte.snap b/crates/biome_html_formatter/tests/specs/html/svelte/each_nested.svelte.snap
index 0a6b4b326826..1db774eb961a 100644
--- a/crates/biome_html_formatter/tests/specs/html/svelte/each_nested.svelte.snap
+++ b/crates/biome_html_formatter/tests/specs/html/svelte/each_nested.svelte.snap
@@ -52,8 +52,6 @@ Self close void elements: never
{/each}
{#each matrix as row}
- {#each row as cell}
- {cell}
- {/each}
+ {#each row as cell}{cell}{/each}
{/each}
```
diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/each_with_destructuring.svelte.snap b/crates/biome_html_formatter/tests/specs/html/svelte/each_with_destructuring.svelte.snap
index 6449115b6fe5..a9bb8158c96e 100644
--- a/crates/biome_html_formatter/tests/specs/html/svelte/each_with_destructuring.svelte.snap
+++ b/crates/biome_html_formatter/tests/specs/html/svelte/each_with_destructuring.svelte.snap
@@ -48,7 +48,7 @@ Self close void elements: never
{/each}
{#each users as { name, email }, i}
- {i}: {name}({email})
+ {i}: {name} ({email})
{/each}
{#each products as [id, title]}
diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/whitespace/issue-8584-w-newline.svelte b/crates/biome_html_formatter/tests/specs/html/svelte/whitespace/issue-8584-w-newline.svelte
new file mode 100644
index 000000000000..ebb3a7eab8c6
--- /dev/null
+++ b/crates/biome_html_formatter/tests/specs/html/svelte/whitespace/issue-8584-w-newline.svelte
@@ -0,0 +1,8 @@
+
+
+
+ Hello, {framework}
+ and Svelte!
+
diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/whitespace/issue-8584-w-newline.svelte.snap b/crates/biome_html_formatter/tests/specs/html/svelte/whitespace/issue-8584-w-newline.svelte.snap
new file mode 100644
index 000000000000..1d3e82ed8645
--- /dev/null
+++ b/crates/biome_html_formatter/tests/specs/html/svelte/whitespace/issue-8584-w-newline.svelte.snap
@@ -0,0 +1,53 @@
+---
+source: crates/biome_formatter_test/src/snapshot_builder.rs
+info: svelte/whitespace/issue-8584-w-newline.svelte
+---
+# Input
+
+```svelte
+
+
+
+ Hello, {framework}
+ and Svelte!
+
+
+```
+
+
+=============================
+
+# Outputs
+
+## Output 1
+
+-----
+Indent style: Tab
+Indent width: 2
+Line ending: LF
+Line width: 80
+Attribute Position: Auto
+Bracket same line: false
+Whitespace sensitivity: css
+Indent script and style: false
+Self close void elements: never
+-----
+
+```svelte
+
+
+
+ Hello, {framework}
+ and Svelte!
+
+```
+
+
+
+## Unimplemented nodes/tokens
+
+"\n\tconst framework = \"Astro\";\n" => 8..37
diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/whitespace/issue-8584.svelte b/crates/biome_html_formatter/tests/specs/html/svelte/whitespace/issue-8584.svelte
new file mode 100644
index 000000000000..f2f4a0a78e3c
--- /dev/null
+++ b/crates/biome_html_formatter/tests/specs/html/svelte/whitespace/issue-8584.svelte
@@ -0,0 +1,5 @@
+
+
+Hello, {framework} and Svelte!
diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/whitespace/issue-8584.svelte.snap b/crates/biome_html_formatter/tests/specs/html/svelte/whitespace/issue-8584.svelte.snap
new file mode 100644
index 000000000000..5a6a5dca609e
--- /dev/null
+++ b/crates/biome_html_formatter/tests/specs/html/svelte/whitespace/issue-8584.svelte.snap
@@ -0,0 +1,47 @@
+---
+source: crates/biome_formatter_test/src/snapshot_builder.rs
+info: svelte/whitespace/issue-8584.svelte
+---
+# Input
+
+```svelte
+
+
+Hello, {framework} and Svelte!
+
+```
+
+
+=============================
+
+# Outputs
+
+## Output 1
+
+-----
+Indent style: Tab
+Indent width: 2
+Line ending: LF
+Line width: 80
+Attribute Position: Auto
+Bracket same line: false
+Whitespace sensitivity: css
+Indent script and style: false
+Self close void elements: never
+-----
+
+```svelte
+
+
+Hello, {framework} and Svelte!
+```
+
+
+
+## Unimplemented nodes/tokens
+
+"\n\tconst framework = \"Astro\";\n" => 8..37
diff --git a/crates/biome_html_formatter/tests/specs/html/whitespace/preserve-newline-after-element.html b/crates/biome_html_formatter/tests/specs/html/whitespace/preserve-newline-after-element.html
new file mode 100644
index 000000000000..8abcb2cfd877
--- /dev/null
+++ b/crates/biome_html_formatter/tests/specs/html/whitespace/preserve-newline-after-element.html
@@ -0,0 +1,4 @@
+
+ Foo
+ Bar
+
diff --git a/crates/biome_html_formatter/tests/specs/html/whitespace/preserve-newline-after-element.html.snap b/crates/biome_html_formatter/tests/specs/html/whitespace/preserve-newline-after-element.html.snap
new file mode 100644
index 000000000000..02f7d5e52aaf
--- /dev/null
+++ b/crates/biome_html_formatter/tests/specs/html/whitespace/preserve-newline-after-element.html.snap
@@ -0,0 +1,39 @@
+---
+source: crates/biome_formatter_test/src/snapshot_builder.rs
+info: whitespace/preserve-newline-after-element.html
+---
+# Input
+
+```html
+
+ Foo
+ Bar
+
+
+```
+
+
+=============================
+
+# Outputs
+
+## Output 1
+
+-----
+Indent style: Tab
+Indent width: 2
+Line ending: LF
+Line width: 80
+Attribute Position: Auto
+Bracket same line: false
+Whitespace sensitivity: css
+Indent script and style: false
+Self close void elements: never
+-----
+
+```html
+
+ Foo
+ Bar
+
+```
diff --git a/crates/biome_html_formatter/tests/specs/html/whitespace/preserve-space-after-element.html b/crates/biome_html_formatter/tests/specs/html/whitespace/preserve-space-after-element.html
new file mode 100644
index 000000000000..2fdad6193134
--- /dev/null
+++ b/crates/biome_html_formatter/tests/specs/html/whitespace/preserve-space-after-element.html
@@ -0,0 +1,3 @@
+
+ Foo Bar
+
diff --git a/crates/biome_html_formatter/tests/specs/html/whitespace/preserve-space-after-element.html.snap b/crates/biome_html_formatter/tests/specs/html/whitespace/preserve-space-after-element.html.snap
new file mode 100644
index 000000000000..0d4f732e9127
--- /dev/null
+++ b/crates/biome_html_formatter/tests/specs/html/whitespace/preserve-space-after-element.html.snap
@@ -0,0 +1,35 @@
+---
+source: crates/biome_formatter_test/src/snapshot_builder.rs
+info: whitespace/preserve-space-after-element.html
+---
+# Input
+
+```html
+
+ Foo Bar
+
+
+```
+
+
+=============================
+
+# Outputs
+
+## Output 1
+
+-----
+Indent style: Tab
+Indent width: 2
+Line ending: LF
+Line width: 80
+Attribute Position: Auto
+Bracket same line: false
+Whitespace sensitivity: css
+Indent script and style: false
+Self close void elements: never
+-----
+
+```html
+Foo Bar
+```
diff --git a/crates/biome_html_formatter/tests/specs/prettier/html/aurelia/basic.html.snap b/crates/biome_html_formatter/tests/specs/prettier/html/aurelia/basic.html.snap
new file mode 100644
index 000000000000..4d5c1e296ccc
--- /dev/null
+++ b/crates/biome_html_formatter/tests/specs/prettier/html/aurelia/basic.html.snap
@@ -0,0 +1,31 @@
+---
+source: crates/biome_formatter_test/src/snapshot_builder.rs
+info: html/aurelia/basic.html
+---
+# Input
+
+```html
+
+
+
+
+```
+
+
+# Prettier differences
+
+```diff
+--- Prettier
++++ Biome
+@@ -1,3 +1 @@
+-
+-
+-
++
+```
+
+# Output
+
+```html
+
+```
diff --git a/crates/biome_html_formatter/tests/specs/prettier/html/case/case.html.snap b/crates/biome_html_formatter/tests/specs/prettier/html/case/case.html.snap
index ed04cfe88396..e682cba9f41c 100644
--- a/crates/biome_html_formatter/tests/specs/prettier/html/case/case.html.snap
+++ b/crates/biome_html_formatter/tests/specs/prettier/html/case/case.html.snap
@@ -36,14 +36,14 @@ info: html/case/case.html
-@@ -7,17 +7,13 @@
+@@ -7,17 +7,12 @@
- Hello world!
+- This is HTML5 Boilerplate.
+ Hello world!
-+
- This is HTML5 Boilerplate.
++
This is HTML5 Boilerplate.