Skip to content

The template language

Nodes

Elements, text, if, for, slot and meta.

The content of a template is a list of nodes: elements, text, conditionals and loops. A component's or element's children are nodes too.

Elements

An element is a name, optionally followed by attributes in parentheses, and then either text or children:

hr
p "Text on the same line is the element's text."
a(href: "/about", class: "underline") "About"
ul(class: "list-disc") {
    li "First"
    li "Second"
}
  • The name decides what it is:
    • a lowercase name is an HTML element (div, p, svg) or one of Weft's own (built-in elements);
    • a capitalised name is a component, looked up in the registry: Button, Card, or one of the app's own (Components and events).
  • The attributes are described in Attributes and values.
  • Text or children, not both. To mix text and elements, give the text its own node:
p {
    "Read the "
    a(href: "/guide") "guide"
    " first."
}

Text

A string on its own is a text node. Its {…} interpolations are evaluated and the result is shown as text, never as HTML:

"Plain text, with {count} interpolated."

if

if shows its block when its condition is truthy, and otherwise its else branch, if any. else if chains:

if items.len == 0 {
    p "Nothing yet."
} else if loading {
    Spinner
} else {
    p "{items.len} items"
}

The condition is any expression, read for its truthiness: false, null, 0, empty text and an empty list are false, and everything else is true.

for

for repeats its block for each item of a list, with the item bound to a name:

ul {
    for post in posts |> filter(p -> p.published) {
        li {
            a(href: post.href) "{post.title}"
        }
    }
}
  • The list is any expression. When it's an expression other than a plain name, null repeats nothing (so for x in items ?? [] is safe); a plain name whose value is null, or anything else that isn't a list, is an error.
  • Inside the block, the name hides any other of the same name.
  • There's no index variable. A list's position is available in its events, as event.index, and in the lambdas of the standard functions that take an index (Standard functions).
  • Events from inside a loop carry the item and its position: event.item and event.index.

slot

In a component's own template, slot marks where the children it's given go. Its block is what it shows when it's given none:

section(class: "rounded-2xl p-6 ring-1 ring-slate-200") {
    slot {
        p "Nothing here yet."
    }
}

The children render in the caller's scope, so they read the caller's names, not the component's. In a layout (app/**/layout.weft), slot is where its pages go.

meta

meta(title: …, description: …) at the top of a page or layout sets the page's title and description. It renders nothing. A page's own meta wins over its layouts'. A meta with name, content, property or itemprop is an ordinary HTML <meta> instead.

meta(title: "Pricing — Lumen", description: "Plans for every team.")
h1 "Pricing"

The values can read the route's parameters: meta(title: "Post: {params.slug}"). See Pages and routing.