Wit

Syntax reference

Every surface form Wit accepts, with its canonical shape, the AST node it produces, and the rule that closes it. This is the "how do I write X" index. For depth on any form, follow its guide link; for the exact node HTML, see the core vocabulary.

Node call forms

A call invokes a node. The parameter style you open with is the style that closes the call — mixing them raises E_MIXED_PARAM_SOURCE.

Call forms and the AST they produce
FormparamsSourcecloseStyleFixture
Bare referencenonebare04 bare-reference
Named body blocknonenamed04 block-name-body
Named body inlinenonenamed04 inline-name-body
Dotted data accessnonebare04 dotted-access
Parensparensparens05 single-named-param
Pipespipesnamed06 basic-named
Record-argrecordparens22 inline-single-field
Form-fill bodyform-fillnamed23 template-invocation
Colon-scatterpipesnamed24 body-scatter-single
Flag parampipes / parens06 flag-with-bang
Opaque pass-throughparensparens20 bare-node-passthrough
Raw literalnonenamedliteral-nodes
Frozen literalnonenamedast.ts frozen

Bare reference

Resolves to a same-named definition. Binds nothing → an unresolved span.

@name

Named body — block and inline

Opener and matching close on their own lines is a block use (body is Block[]). Mid-paragraph it is an inlineuse (inline: true, body is Inline[]).

source
@blockquote
A quotation, set apart.
blockquote@

An @em inline em@ mark sits mid-sentence.
result

A quotation, set apart.

An inline mark sits mid-sentence.

Dotted data access

Binds a data def, not a node def. Numeric segments index a collection. Unresolved → <span class="wit-unresolved">@a.b</span>.

@author.name
@sales.0.region

Parens

Self-closing. Space-separated or colon keys. A multi-word colon value must be quoted.

@img(src photo.jpg, alt A photo)
@h2(id intro, class lead) Title h2@
@x(k: "a b")

Pipes

Each pipe is one parameter; duplicate keys are last-one-wins. Closed by name@.

source
@a |href /docs| |target _blank| Read the docs a@

Record-arg

An inline or multi-line record as the argument; self-closing. Hyphen or colon delimiter is accepted at a call site.

@card { title - Q3, status - shipped }

Form-fill body

A bare opener followed by key: value lines. Needs two or more content lines, or it is read as prose.

@contact
name: Ada Lovelace
role: Author
contact@

Colon-scatter

A single-line body of k:v tokens (no space after the colon). Surfaces internally as paramsSource: pipes. A space after the colon is prose.

@badge status:new priority:high badge@

Flag param

A valueless parameter: a trailing bang in a pipe, or a bare flag in parens.

@task |title Ship| |urgent!| task@

Opaque pass-through

The universal container. If type names a core-vocab node it renders as that element; otherwise it emits a <div> carrying every named param as data-*.

source
@node(type h2) A heading node@
@node(type box, role note) Body node@
result

A heading

Body

Raw and frozen literals

@@name … name@@ makes the body one verbatim Text node (raw); {{path}} holes still expand. @@@name … name@@@ adds frozen — even {{…}} passes through untouched.

source
@@style .lead { font-size: 1.2rem } style@@
result

Definition forms

A definition declares a reusable node or a named value. Opens with a hash.

Definition forms and the AST they produce
FormAST shapeNoteFixture
Single-line defsingle-lineone-line template07 single-line-def
Value-block defvalue-blockclosed by a double bang07 multi-line-value
Block defblockuses the body slot07 block-definition
Capture listblockdeclares captures07 multi-capture-list
Additive partialblock / singlemerges across the file08 simple-additive-prefix
Data def recorddataDefhyphen delimiter required09 records
Data def collectiondataDefordered list10 collections
Data def scalardataDefnumber / bool / null / prose09 scalar-types
#lead: A one-line reusable value.

#abstract:
A multi-line value,
closed by two bangs.
!!

#callout ||label, body||
@aside(class ::label::)
...
aside@
callout#

+#authors: Ada
+#authors: Grace

#site: { name - Docs, year - 2026 }
#tags: [ ref, spec, wit ]
#count: 42

Other constructs

Other constructs
ConstructRenders asFixture
Emphasisstrong / em02 emphasis
Interpolationthe captured param07 captures-and-interpolation
Raw-body holeexpand-time value in raw bodiesliteral-nodes
Body slotthe invocation body07 body-slot
Commentomitted from output03 comments
Reference directivepulled-in defs15 references
Conditionalkept or dropped body12 conditionals
Iterationrepeated body13 iteration
Scripteffects only — no output15 scripting
Escapethe literal char00 lexical
External dataa bound data defdata-loader
Wrap *bold* and _italic_ inline.

::name::

{{theme.accent}}

~ this line is a comment

reference "shared/defs.wit"

(if @author) By @author.name (end)
(if @status is shipped) Live (else) Draft (end)

(each @tags as tag) @li ::tag:: li@ (end)

<% total = lh.data.a + lh.data.b %>

\* a literal asterisk, not a mark

@load env load@
@load sales |as rows| |region West| load@

The equivalence proof

One template, every call form

: fixture 26-all-param-forms/showcase.wit invokes the same node thirteen ways and asserts identical output. Form 13 (self-closing pipes) is placed last on purpose — pipes with no same-line close greedily bind to the next close, so ordering is a real constraint, not a parser quirk.

See also

Core vocabulary

· Data model · Tables · Gotchas · Glossary · Cheatsheet.