How can I prevent an HTML p tag from being generated magically?

I have also been tormented by this problem. :heart:
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>
1 Like