I have also been tormented by this problem. ![]()
In my case, I used xml to read an existing html and found the exported html is different. (#5890)
The cause is that Typst wraps inline-level content in a paragraph:
The rules for when Typst wraps inline-level content in a paragraph are as follows:
- All text at the root of a document is wrapped in paragraphs.
- Text in a container (like a
block) is only wrapped in a paragraph if the container holds any block-level content. If all of the contents are inline-level, no paragraph is created.
The criterion of inline-level is in typst/crates/typst-html/src/tag.rs at a4be7778e5bbc443f54c963711187470de2decc0 · typst/typst · GitHub.
/// Whether the element is inline-level as opposed to being block-level.
///
/// Not sure whether this distinction really makes sense. But we somehow
/// need to decide what to put into automatic paragraphs. A `<strong>`
/// should merged into a paragraph created by realization, but a `<div>`
/// shouldn't.
///
/// <https://www.w3.org/TR/html401/struct/global.html#block-inline>
/// <https://developer.mozilla.org/en-US/docs/Glossary/Inline-level_content>
/// <https://github.com/orgs/mdn/discussions/353>
pub fn is_inline_by_default(tag: HtmlTag) -> bool {
matches!(
tag,
self::abbr | self::a | self::bdi | self::b | self::br | self::bdo
| self::code | self::cite | self::dfn | self::data | self::i
| self::em | self::mark | self::kbd | self::rp | self::q
| self::ruby | self::rt | self::samp | self::s | self::span
| self::small // 👈
| self::sub | self::strong | self::time | self::sup | self::var | self::u
)
}
- It does not take CSS into account
<input>and<label>are considered block-level<small>is considered inline-level
As a result, <small> is wrapped with a <p>.
Workaround
Put block-level tags in <span>.
#{
html.span(html.label(
html.input(),
))
html.small[aaaaa]
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<!-- Spaces are added by me. -->
<p>
<span>
<label><input></label>
</span>
<small>aaaaa</small>
</p>
</body>
</html>