Wit

Literal & raw nodes; custom CSS

A raw node embeds content verbatim — code, foreign markup, a themed stylesheet. Doubling the marker to @@name freezes Wit syntax inside the body; tripling it to @@@name freezes even the {{…}} interpolation holes. The freeze level is how you choose how much processing the body receives.

A literal body

Inside @@name … name@@, every Wit construct is inert — an @, #, _, *, or ::hole:: is just text:

source
@@code
let x = @not_a_node;
code@@
result
let x = @not_a_node;

That renders the line literally, @not_a_node and all.

Block or inline

A raw node is a block when a newline directly follows the opening @@name, and inline otherwise. The first literal name@@ closes it; if none appears, that is E_UNCLOSED_RAW_NODE. One whitespace character at each boundary is trimmed.

Names map to elements

A raw node named after a known HTML tag emits that element — @@@code becomes <code>, @@pre becomes <pre>. A custom name becomes a <div> carrying class="wit-node" and a data-wit-name attribute. Bodies are HTML-escaped, except for @@style and @@script, which are emitted as raw text (with a break-out guard against a stray closing tag).

The three freeze levels

  • One marker@name — is an ordinary node: live Wit, and no interpolation (prose is not an interpolation context).
  • Two markers@@name — freezes Wit but keeps {{…}} live.
  • Three markers@@@name — freezes both.

This is why {{path}} is live only inside a raw node body — it is the one place interpolation resolves.

Themed CSS with interpolation

The flagship use: drive a stylesheet from a data definition.

source
#theme: { accent - green }

@@style
.badge { color: {{theme.accent}}; }
style@@
result

That renders .badge { color: green; } — the {{theme.accent}} resolves because @@style is a two-marker raw node. Triple it and the hole stays literal:

source
@@@code {{x}} code@@@   ~ renders the literal text {{x}}
result

{{x}} ~ renders the literal text {{x}}

Not shipped: component defs

You may see ##name … name## raw-component definitions in older notes. They are roadmap, not shipped — there is no ## token today. Do not rely on them.

Common mistakes

  • Expecting {{…}} to be live in prose — it is live only inside a raw node body.
  • Freezing a table you want resolved from data.
  • Documenting ## component defs as if they shipped.

See also

Interpolation & captures

· Derived content · Escapes