Directives

The Longform Markup Language supports custom directives which can hook into the program invoking the parser. Stat defines a useful core set of directives which are helpful for static site generation. You can also define your own which extend Longform's capabilities.

Some directives allow meta information to be defined in a document and make it available in other contexts as accessors. Others define their own DSLs, asynchronously call external tools, render their own markup, and embed it at the location they are called.

This page documents the directives defined in the @stat namespace. Stat will evolve, but it is supposed to remain simple and low dependency. If you requirements move beyond the directives Stat provides, you can create your own _directives directory. Stat will assume any objects exported by modules in that directory define directives, and will make them available to your Longform documents.

The Longform Markup Language Spec has more information on the standard set of directives. And you can look at Stat's source code and the Longform parser's typescript source for how they are defined.

Longform directives can take inline args and block args as arguments. Inline arguments appear on the line of the directive's statement. Block args follow the directive statement, indented out by two spaces.

@custom:directive:: These are my inline args.
  These are my block args.
  Block args can span many lines.
  
  And contain blank lines

Note that while block args support blank likes, the @longform/async parser currently does not capture them unless there is whitespace in the line.

Stat's directives

@stat:title§

Sets the title of the document. Typically this would be rendered into a HTML page's <title> element by the layout using the same directive.

@lang:: en
@stat:title:: My First Blog Post

@stat:title can use both the inline and / or block args when setting the document's title. If both are used they will be space separated, as are all lines the title spans in the block args.

@stat:title can only be set in the head of a document.

@doctype:: html
html[lang=@lang]::
  head::
    title:: @stat:title

@stat:title can be used as an accessor in Longform attribute declarations, and in text rendering positions.

@stat:date§

Sets the publication date of the document. This can be used as an accessor like the @stat:title directive, but is also used by other directives like @stat:paginate when sorting of pages is required.

@lang:: en
@stat:date:: 2026-05-10
@stat:title:: My First Blog Post
@stat:description::
  This is the description of my first blog post.

@stat:date must be set using the inline args. and can only be set in the head of a document.

@stat:description§

Sets the description of the document. Typically this would be rendered into a HTML page's <meta name=description> element by the layout using the same directive.

@lang:: en
@stat:title:: My First Blog Post
@stat:description::
  This is the description of my first blog post.

@stat:description can use both the inline and / or block args when setting the document's title. If both are used they will be space separated, as are all lines the title spans in the block args.

@stat:description can only be set in the head of a document.

@doctype:: html
html[lang=@lang]::
  head::
    title:: @stat:title
    meta::
      [name=description]
      [content=@stat:description]

@stat:description can be used as an accessor in Longform attribute declarations, and in text rendering positions.

@stat:rich-description§

Sets the rich description of the document. It can be used as an accessor and defaults to the @stat:description if not declared for a page.

@lang:: en
@stat:title:: My First Blog Post
@stat:description::
  This is the description of my first blog post.
@stat:rich-description::
  p::
    This is a description that includes <em>Longform</em> markup.

@stat:rich-description must be defined using the block args. It can only be set in the head of a document.

@stat:layout§

By default every page uses the _src/layouts/default.lf layout to render the page. The @stat:layout directive can be used to pick another layout from the layouts directory.

@lang:: en
@stat:date:: 2026-05-10
@stat:layout:: custom-layout

The @stat:layout directive should be used The file name of the layout should be provided with no longform extension.

@lang:: en
@stat:title:: Blog posts
@stat:description::
  This is the description of my first blog post.

@stat:title can use both the inline and / or block args when setting the document's title. If both are used they will be space separated, as are all lines the title spans in the block args.

@stat:title can only be set in the head of a document.

@doctype:: html
html[lang=@lang]::
  head::
    title:: @stat:title
    meta::
      [name=description]
      [content=@stat:description]

@stat:title can be used as an accessor in Longform attribute declarations, and in text rendering positions.

@stat:current-page§

This directive is used in re-useable contexts, like layouts, to detect if an <a href> is pointing to the current page. If the element's href is, then the aria-current=page attribute is automatically added to the <a href> element.

If the Longform element chains other elements, the @stat:current-page directive will search within the chained elements for an <a href> element to modify.

nav::
  ul::
    @stat:current-page
    li::a[href=/]:: Home
    
    @stat:current-page
    li::a[href=/directives]:: Directives

Stat knows each URL for each document before it processes the layout, so it can correctly assign aria-current=page values.

@stat:source§

Inlines the source code of a file. The file path defined in the directive's inline args should always be relative to the project root.

@doctype:: html
html[lang=@lang]::
  head::
    title:: @stat:title
    meta::
      [name=description]
      [content=@stat:description]
    style::
      @stat:source:: main.css

In this example the source code of the main.css file is embedded directly into the <style> element, instead of using a <link rel=stylesheet> element. This prevents the flashing of unstyled content, but does increase the HTML file size.

section::
  h2:: Stat Templates
  figure::
    figcaption:: The default template
    pre::code::
      @stat:source:: _src/layouts/default.lf

This example embeds the _src/layouts/default.lf file into the markup as example code.

@stat:paginate§

When used in the head of the document the @stat:paginate directive provides a directory to paginate over. All files in the directory, except The index.lf page will be included in the paged listing if they have a @stat:date set in their page head. And the pages will be order from most recent to last.

When used as a render directive it is used to provide a Longform template that is rendered for each page targeted via pagination. All values defined in the target page's head are available as template arguments.

The targeted page's URL will also be made available to the template using the stat:url variable name.

@lang:: en
@stat:title:: Articles
@stat:paginate:: /articles

#pages
section::
  h2:: Articles
  @paginate::
    article.card[id=#{stat:key}]::
      h3.card-header:: #{stat:title}
      div.card-body::
        ##{stat:rich-description}
      footer::
        a[href=#{stat:url}]:: View more

Note that the Longform parser is yet to support the ##{stat:rich-description} for templating markup.

@stat:prev and @stat:next§

The @stat:prev and @stat:next directives allow conditional rendering of previous and next links and access to the URL of the pages being linked to.

The @stat:is-final directive can be used at the start of the directive's block args to define a fallback markup, incase the pagination list has been exhausted in the parent directive's direction.

The @stat:prev and @stat:next directives can only be used in a page where @stat:paginate is used in the page's head.

@lang:: en
@stat:title:: Articles
@stat:paginate:: /articles

#pages
section::
  h2:: Articles
  @paginate::
    article.card[id=#{stat:key}]::
      h3.card-header:: #{stat:title}
      div.card-body::
        ##{stat:rich-description}
      footer::
        a[href=#{stat:url}]:: View more
  
  div.control-group::
    @stat:prev::
      @stat:is-final::
        button.button[disabled=true]:: Prev
      a.button:: Prev
        [href=#{stat:url}]
        [rel=prev]
    @stat:next::
      @stat:is-final::
        button.button[disabled=true]:: Next
      a.button:: Next
        [href=#{stat:url}]
        [rel=next]