Skip to content

Bug: SGML.Text cannot be used inside @Builder<PhrasingContent> or @Builder<FlowContent> closures #32

@mynona

Description

@mynona

Bug: SGML.Text cannot be used inside @Builder<PhrasingContent> or @Builder<FlowContent> closures

Package: swift-web-standards
Type: Missing conformance / bug
Severity: High — Text(...) cannot be used in most HTML element builders, making basic text rendering verbose

Description

SGML.Text is the fundamental text node type, but it does not conform to PhrasingContent or FlowContent. Most HTML elements with typed builders (e.g. P {}, H1 {}, Span {}, Kbd {}, Li {}) use @Builder<PhrasingContent>, which means plain Text("...") cannot be placed inside them:

P {
    Text("Hello, world!")
    // ❌ error: cannot convert value of type 'Text' to expected argument type '[any PhrasingContent]'
}

H1 {
    Text("Page title")
    // ❌ same error
}

Per the HTML5 spec, text nodes are always phrasing content (spec §3.2.6.2).

This also affects @Builder<FlowContent> closures (e.g. Div {}, Body {}).

Workaround

Declare retroactive conformances in the consuming package:

import SGML
import HTML

extension SGML.Text: @retroactive PhrasingContent {}
extension SGML.Text: @retroactive FlowContent {}

Suggested fix

In the HTML module, add:

extension SGML.Text: PhrasingContent {}
extension SGML.Text: FlowContent {}

SGML.Text has no attributes and no children, so these conformances are purely categorical — no additional implementation is needed beyond what Element already provides.

Impact

Without this fix, any usage of multiple inline text nodes inside a typed builder requires wrapping each in a Span, even when no styling is needed:

// Workaround (verbose and semantically incorrect):
P {
    Span("Price: ")
    Span("$42")
}

// What should work:
P {
    Text("Price: ")
    Text("$42")
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions