> ## Documentation Index
> Fetch the complete documentation index at: https://gtmsdk.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Fix: Sanity Portable Text empty marked spans no longer render as a horizontal rule

> An empty span carrying a strong or em mark emitted bare delimiter runs — a lone **** line, or ____ once consecutive empty em spans joined — which re-parsed as a CommonMark thematic break; empty spans now take the existing HTML fallback and emit inert HTML elements.

## Bug fixes

**Empty marked spans in Sanity Portable Text (issue #885)**

`libs/sanity/portable_text.py` wraps `strong`-marked span text in `**`
delimiters and `em`-marked text in `_`, unless the text touches edge
whitespace, in which case it falls back to HTML. An *empty* span slipped
between the two: `_EDGE_WS_RE` (`^\s|\s$`) needs a character to match, and
`""` has none, so the empty span took the delimiter path and emitted `****`.
A line consisting of `****` is a CommonMark thematic break (§4.1), so a
block whose only content was an empty bold run — or one sitting next to a
span ending in a newline — rendered as `<hr/>` instead of nothing.

The empty-span case now joins the existing HTML fallback (the same mechanism
PR #775 added for edge whitespace, applied to the zero-length degenerate
class) and emits an inert `<strong></strong>`.

The `em` branch first looked safe: a lone `__` is two delimiters — too short
for a thematic break and unable to pair into emphasis. That holds only for a
single span, though. `_render_spans` joins adjacent span output with no
separator, so consecutive empty `em` spans join into `____` (or `__ __`
across a whitespace span), which §4.1 also accepts as a thematic break — the
same `<hr/>` fallout via one more span. Found in review of this change; empty
`em` spans now take the same fallback and emit an inert `<em></em>`.

The trigger requires a hand-edited Portable Text document (the Studio editor
serializes an empty selection as no span rather than an empty marked one), so
this is defense-in-depth for the blog-archive converter, not an
observed-data regression.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.