Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/strophe/strophejs/llms.txt

Use this file to discover all available pages before exploring further.

The stx tagged template literal and the Stanza class it returns offer a modern, declarative way to construct XMPP stanzas. Instead of chaining method calls as with Builder, you write XML inline as a template literal and embed dynamic values directly with ${...} interpolation. All interpolated string values are automatically XML-escaped, so user-supplied content cannot inject malformed XML or break stanza structure. The stx API was introduced in Strophe.js 3.1.0 and is the recommended approach when you prefer readable inline XML over the fluent builder pattern.

stx Tagged Template Literal

stx(strings: TemplateStringsArray, ...values: StanzaValue[]): Stanza
The stx function is a tagged template literal that turns an inline XML template into a Stanza instance. It is exported from strophe.js and registered on globalThis as stx.

How it works

Each ${value} slot in the template is processed according to its type before the final XML string is assembled:
Value typeBehaviour
stringXML-escaped (e.g. <&lt;)
numberCoerced to string, then XML-escaped
null / undefinedTreated as an empty string ("")
StanzaSerialized via .toString() — not re-escaped
BuilderSerialized via .toString() — not re-escaped
UnsafeXMLEmbedded verbatim — not escaped
StanzaValue[]Each element processed by the same rules
Only string (and number) values are escaped. Nested Stanza and Builder objects are trusted to already produce valid XML. If you must embed a raw XML string, use Stanza.unsafeXML() to mark it explicitly as trusted.

Parameters

strings
TemplateStringsArray
required
The static string fragments of the template literal, provided automatically by the JavaScript engine.
values
StanzaValue[]
required
The interpolated values, each of which is string | Stanza | Builder | UnsafeXML | StanzaValue[].
returns
Stanza
A new Stanza instance that lazily builds its DOM tree on first access.

Basic usage

import { stx } from 'strophe.js';

// userInput is automatically XML-escaped — no injection possible
const userInput = '<script>alert("xss")</script>';

const msg = stx`<message to='alice@example.org' type='chat'>
    <body>${userInput}</body>
</message>`;

connection.send(msg);
// The body text is safely escaped: &lt;script&gt;alert("xss")&lt;/script&gt;

Multi-line stanza

import { stx } from 'strophe.js';

const msg = stx`<message
    from='sender@example.org'
    id='hgn27af1'
    to='recipient@example.org'
    type='chat'>
    <body>Hello world</body>
</message>`;

connection.send(msg);

Nested Stanza interpolation

You can embed one stx-produced stanza inside another. The inner stanza’s XML is inserted verbatim without re-escaping:
import { stx } from 'strophe.js';

const body = stx`<body>Hello!</body>`;

const msg = stx`<message to='alice@example.org' type='chat'>${body}</message>`;
connection.send(msg);

Array of stanzas

Interpolating an array of Stanza or Builder objects concatenates their XML representations in order:
import { stx } from 'strophe.js';

const items = ['romeo@example.net', 'juliet@example.com'].map(
    (jid) => stx`<item jid='${jid}'/>`
);

const query = stx`<iq type='set' id='r1' xmlns='jabber:client'>
    <query xmlns='jabber:iq:roster'>${items}</query>
</iq>`;

StanzaValue Type

type StanzaValue = string | Stanza | Builder | UnsafeXML | StanzaValue[];
The union type accepted as interpolated values inside stx templates. Recursive arrays allow you to spread lists of child stanzas naturally.

Stanza Class

Stanza extends Builder and represents an XML stanza constructed from a tagged template literal. You will not normally instantiate Stanza directly — use the stx tag function instead.

Constructor

constructor(strings: TemplateStringsArray, values: StanzaValue[])
Do not call the Stanza constructor directly. Use the stx tagged template literal, which calls this constructor for you.
strings
TemplateStringsArray
required
The static string segments of the template, supplied automatically by the JavaScript runtime.
values
StanzaValue[]
required
The dynamic values interpolated into the template.

toString()

toString(): string
Assembles the final XML string by interleaving the static template fragments with the (appropriately escaped or serialized) dynamic values. The result is memoized after the first call.
returns
string
The complete XML string representation of the stanza, trimmed of leading/trailing whitespace.
const pres = stx`<presence type="${'available'}" xmlns="jabber:client"/>`;
console.log(pres.toString());
// <presence type="available" xmlns="jabber:client"/>

buildTree()

buildTree(): Element
Builds and returns the root DOM Element for this stanza. Internally it calls Stanza.toElement(this.toString(), true), so an invalid XML string or wrong namespace will throw immediately.
returns
Element
The root DOM Element of the parsed stanza.
const iq = stx`<iq type='get' id='ping1' xmlns='jabber:client'>
    <ping xmlns='urn:ietf:params:xml:ns:xmpp-ping'/>
</iq>`;

const el: Element = iq.buildTree();
connection.send(el);

Stanza.toElement(string, throwErrorIfInvalidNS?)

static toElement(string: string, throwErrorIfInvalidNS?: boolean): Element
Parses an XML string into a DOM Element. For <message/>, <iq/>, and <presence/> elements it also validates that the namespace is jabber:client or jabber:server; a wrong namespace either logs an error or throws, depending on the second argument.
string
string
required
A well-formed XML string to parse. Throws a Parser Error if the XML is invalid.
throwErrorIfInvalidNS
boolean
When true, an invalid namespaceURI on a core stanza element throws an Error instead of logging. Defaults to undefined (falsy — logs only).
returns
Element
The first element child of the parsed document, with leading/trailing whitespace-only text nodes stripped.
import { Stanza } from 'strophe.js';

const el = Stanza.toElement(
    "<message to='bob@example.org' xmlns='jabber:client'/>",
    true
);
console.log(el.nodeName); // "message"

Stanza.unsafeXML(string)

static unsafeXML(string: string): UnsafeXML
Wraps a raw XML string in an UnsafeXML marker object. When an UnsafeXML value is interpolated into an stx template, it is embedded verbatim — no escaping is applied.
string
string
required
A raw XML string to embed without escaping. Must be valid XML in the context where it is used.
returns
UnsafeXML
An UnsafeXML instance (a subclass of String) that signals to stx to skip escaping.
Only pass trusted, application-controlled strings to Stanza.unsafeXML(). User-supplied content must never be marked as UnsafeXML — doing so can allow XML injection attacks that corrupt or hijack XMPP sessions.
import { stx, Stanza } from 'strophe.js';

const status = '<status>I am busy!</status>';

const pres = stx`
  <presence from='juliet@example.com/chamber'>
    ${Stanza.unsafeXML(status)}
  </presence>`;

connection.send(pres);

UnsafeXML Class

class UnsafeXML extends String {}
UnsafeXML is a thin subclass of the built-in String type. Its sole purpose is to carry a type-level marker that tells stx to embed the string without escaping. Instances are created exclusively through Stanza.unsafeXML() — do not call new UnsafeXML(...) directly.
This class exists for advanced use-cases where you control the XML source (e.g. re-serializing a stanza you previously built and serialized yourself). Treat it as a security boundary: crossing it with untrusted data breaks all injection protections stx provides.

toStanza Utility Function

const toStanza = Stanza.toElement;
toStanza is a convenience alias for Stanza.toElement, exported from strophe.js and registered on globalThis. Use it when you need to parse a raw XML string into a DOM element outside of a stx template.
import { toStanza } from 'strophe.js';

const el = toStanza("<presence from='romeo@example.net' xmlns='jabber:client'/>");
connection.send(el);

Complete Examples

Sending a chat message with safe user input

import { stx } from 'strophe.js';

const userInput = prompt('Message text:') ?? '';

const msg = stx`<message to='alice@example.org' type='chat'><body>${userInput}</body></message>`;
connection.send(msg);

Embedding a nested child stanza

import { stx } from 'strophe.js';

const body = stx`<body>Hello!</body>`;
const msg = stx`<message to='alice@example.org' type='chat'>${body}</message>`;
connection.send(msg);

Presence with trusted raw XML content

import { stx, Stanza } from 'strophe.js';

const status = '<status>I am busy!</status>';

const pres = stx`
  <presence from='juliet@example.com/chamber'>
    ${Stanza.unsafeXML(status)}
  </presence>`;

connection.send(pres);

Presence with dynamic show and status values

import { stx } from 'strophe.js';

const show = 'dnd';
const statusText = 'In a meeting';

const pres = stx`<presence type="available" xmlns="jabber:client">
    <show>${show}</show>
    <status>${statusText}</status>
</presence>`;

connection.send(pres);

Parsing a received XML string

import { Stanza, toStanza } from 'strophe.js';

// Both forms are equivalent:
const el1 = Stanza.toElement("<iq type='result' id='q1' xmlns='jabber:client'/>", true);
const el2 = toStanza("<iq type='result' id='q1' xmlns='jabber:client'/>");

Build docs developers (and LLMs) love