diff --git a/docs/users/changelog.md b/docs/users/changelog.md
index 49794ba..afc7b28 100644
--- a/docs/users/changelog.md
+++ b/docs/users/changelog.md
@@ -8,6 +8,9 @@ Note that there is currently no guarantee for a stable Markdown formatting style
- Deprecated
- Plugin interface: `mdformat.plugins.ParserExtensionInterface.add_cli_options`.
The replacing interface is `mdformat.plugins.ParserExtensionInterface.add_cli_argument_group`.
+- Fixed
+ - Incorrect line wrap on lines right after a hard break.
+ Thank you, [MDW](https://github.com/mdeweerd), for the issue.
- Added
- Plugin interface: `mdformat.plugins.ParserExtensionInterface.add_cli_argument_group`.
With this plugins can now read CLI arguments merged with values from `.mdformat.toml`.
diff --git a/src/mdformat/renderer/_context.py b/src/mdformat/renderer/_context.py
index b9a4da7..89140b1 100644
--- a/src/mdformat/renderer/_context.py
+++ b/src/mdformat/renderer/_context.py
@@ -387,7 +387,14 @@ def paragraph(node: RenderTreeNode, context: RenderContext) -> str: # noqa: C90
if isinstance(wrap_mode, int):
wrap_mode -= context.env["indent_width"]
wrap_mode = max(1, wrap_mode)
- text = _wrap(text, width=wrap_mode)
+ # Newlines should be mostly WRAP_POINTs by now, but there are
+ # exceptional newlines that need to be preserved:
+ # - hard breaks: newline defines the hard break
+ # - html inline: newline vs space can be the difference between
+ # html block and html inline
+ # Split the text and word wrap each section separately.
+ sections = text.split("\n")
+ text = "\n".join(_wrap(s, width=wrap_mode) for s in sections)
# A paragraph can start or end in whitespace e.g. if the whitespace was
# in decimal representation form. We need to re-decimalify it, one reason being
diff --git a/tests/data/wrap_width_50.md b/tests/data/wrap_width_50.md
index ec0d7c9..a75a155 100644
--- a/tests/data/wrap_width_50.md
+++ b/tests/data/wrap_width_50.md
@@ -134,3 +134,49 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa No-wrap-points-until-
Unicode whitespace shouldnt act as wrap point, the
normal space should
.
+
+
+Hard break (issue #326)
+.
+Loremiiinoeffefe\
+ipsum dolor sit amet, consectetur adip elitismisun.
+
+Here's 50 chars including hardbreak backslashhhhh\
+ipsum dolor sit amet, consectetur adip elitismisun.
+
+Here's 50 chars before hardbreak backslash ggggggg\
+ipsum dolor sit amet, consectetur adip elitismisun.
+.
+Loremiiinoeffefe\
+ipsum dolor sit amet, consectetur adip
+elitismisun.
+
+Here's 50 chars including hardbreak backslashhhhh\
+ipsum dolor sit amet, consectetur adip
+elitismisun.
+
+Here's 50 chars before hardbreak backslash
+ggggggg\
+ipsum dolor sit amet, consectetur adip
+elitismisun.
+.
+
+
+Newline in HTML inline
+.
+There is no hard break here, only HTML inlineee ipsum dolor sit amet, consectetur adip elitismisun.
+
+sssssssssssssssssssssssssssssssssssss backslash ipsum dolor sit amet, consectetur adip elitismisun.
+.
+There is no hard break here, only HTML inlineee
+ ipsum dolor sit amet, consectetur adip
+elitismisun.
+
+sssssssssssssssssssssssssssssssssssss backslash
+ ipsum dolor sit amet, consectetur adip
+elitismisun.
+.
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 6c4870c..77c8824 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -241,7 +241,6 @@ def test_consecutive_wrap_width_lines(tmp_path):
assert file_path.read_text() == text
-@pytest.mark.xfail(reason="https://github.com/executablebooks/mdformat/issues/326")
def test_wrap__hard_break(tmp_path):
file_path = tmp_path / "test_markdown.md"
file_path.write_text(