On this page:
5.5.1 Rendering custom elements
5.5.2 HTML
doc->html
doc->html-xexpr
default-html-tag
punct-html-render%
5.5.3 Typst
doc->typst
default-typst-tag
escape-typst-text
escape-typst-string
punct-typst-render%
5.5.4 Plain text
doc->plaintext
make-plaintext-fallback
5.5.5 Base renderer
punct-abstract-render%
new
render-document
render-string
render-thematic-break
render-heading
render-code-block
render-html-block
render-paragraph
render-blockquote
render-itemization
render-item
render-line-break
render-bold
render-italic
render-code
render-link
render-image
render-html
render-footnote-reference
render-footnote-definition

5.5 Rendering🔗

Punct currently includes renderers for HTML, Typst, and plain-text. These are based on a "base" renderer class that you can extend to customize the rendering process or to target new output formats.

5.5.1 Rendering custom elements🔗

When rendering your document to a specific output format (such as HTML) Punct has to decide how to render any custom elements introduced by your code. When Punct encounters a custom element, it passes it to a fallback function: the fallback function receives three arguments: the custom element’s tag, its attributes, and a list of sub-elements found inside the element. The sub-elements will already have been fully processed by Punct.

A separate fallback function is needed for each output format you want to target. Punct provides default fallback functions the target output format it supports natively. For example, when targeting HTML, Punct defaults to default-html-tag, which simply converts custom elements to HTML elements. If you want more customized behavior, you’ll need to provide your own fallback procedure to the renderer.

Here’s an example pair of functions for rendering documents containing the custom abbreviation element (from the examples above) into HTML:

(define (custom-html tag attrs elems)
  (match (list tag attrs)
    [`(abbreviation [[term ,term]]) `(abbr [[title ,term]] ,@elems)]))
 
(define (my-html-renderer source-path)
  (doc->html (get-doc source-path) custom-html))

5.5.2 HTML🔗

 (require punct/render/html) package: punct-lib

procedure

(doc->html pdoc [fallback]) → string?

  pdoc : document?
  fallback : 
(-> symbol?
    (listof (list/c symbol? string?))
    (listof xexpr?)
    xexpr?)
   = default-html-tag
Renders pdoc into a string containing HTML markup. Each custom element is passed to fallback, which must return an X-expression.

This function uses xexpr->string to generate the HTML string. This function will blindly escape characters inside <script> and <style> tags, which may introduce errors. For HTML output that is friendlier and more correct, consider using the html-printer package in concert with doc->html-xexpr.

For more information on using the fallback argument to render custom elements, see Rendering custom elements.

procedure

(doc->html-xexpr pdoc [fallback]) → xexpr?

  pdoc : document?
  fallback : 
(-> symbol?
    (listof (list/c symbol? string?))
    (listof xexpr?)
    xexpr?)
   = default-html-tag
Renders pdoc into HTML, but in X-expression form rather than as a string. Each custom element is passed to fallback, which must itself return an X-expression.

For more information on using the fallback argument to render custom elements, see Rendering custom elements.

procedure

(default-html-tag tag attributes elements) → xexpr?

  tag : symbol?
  attributes : (listof (list/c symbol? string?))
  elements : (listof xexpr?)
Returns an X-expression comprised of tag, attributes and elements. Mainly used as the default fallback function for doc->html.

Examples:
> (require punct/render/html)
> (default-html-tag 'kbd '() '("Enter"))

'(kbd "Enter")

> (default-html-tag 'a '((href "http://example.com")) '("Link"))

'(a ((href "http://example.com")) "Link")

The HTML renderer class. Extends punct-abstract-render% to produce HTML output. You can extend this class to customize HTML rendering behavior.
See Extending the Renderer for examples of extending the HTML renderer.

5.5.3 Typst🔗

 (require punct/render/typst) package: punct-lib

Typst is a modern typesetting system designed as an alternative to LaTeX. This renderer produces Typst markup from Punct documents.

procedure

(doc->typst pdoc [fallback]) → string?

  pdoc : document?
  fallback : (symbol? (listof (listof symbol? string?)) list? . -> . string?)
   = default-typst-tag
Renders pdoc into a string containing Typst markup. Any custom elements are passed to fallback, which must return a string.

Markdown/Punct elements are mapped to Typst syntax as follows:

Punct element

Typst output

Headings

= Heading (with levels as = count)

Bold

*text*

Italic

_text_

Inline code

`code`

Code blocks

```lang ... ```

Links

#link("url")[text]

Images

#image("path")

Bullet lists

- item

Numbered lists

+ item

Block quotes

#quote(block: true)[...]

Footnotes

#footnote[...] (inline)

Typst special characters (*, _, `, #, @, $, [, ]) in text content are automatically escaped, allowing the same Punct source to target both HTML and Typst without manual escaping. Content inside code blocks and inline code is not escaped, as Typst renders these literally.

For more information on using the fallback argument to render custom elements, see Rendering custom elements.

Added in version 1.4 of package punct-lib.

procedure

(default-typst-tag tag attributes elements) → string?

  tag : symbol?
  attributes : (listof (listof symbol? string?))
  elements : list?
Returns a Typst function call string using tag, attributes, and elements. Mainly used as the default fallback function for doc->typst.

The output format is #tag(attr: "val", ...)[content], where attributes become named arguments with string values, and elements become a trailing content block. When there are no attributes, the parentheses are omitted: #tag[content]. When there are no elements, the content block is omitted: #tag(attr: "val").

Hyphens in tag and attribute names are converted to underscores to produce valid Typst identifiers (e.g., 'my-element becomes my_element).

Note that elements are already escaped when passed to the fallback. Attribute values are automatically escaped and quoted as Typst strings.

Examples:
> (require punct/render/typst)
> (default-typst-tag 'note '() '("Important!"))

"#note[Important!]"

> (default-typst-tag 'note '((class "info")) '("Important!"))

"#note(class: \"info\")[Important!]"

> (default-typst-tag 'my-spacer '((line-height "2em")) '())

"#my_spacer(line_height: \"2em\")"

Added in version 1.4 of package punct-lib.

procedure

(escape-typst-text str) → string?

  str : string?
Escapes special Typst characters (*, _, `, #, @, $, [, ], \) in str by prefixing them with backslashes. Use this for text content in custom fallback procedures.

Added in version 1.4 of package punct-lib.

procedure

(escape-typst-string str) → string?

  str : string?
Escapes backslashes and double quotes in str for use within quoted Typst strings (e.g., URLs or file paths in function arguments like #link("...") or #image("...")).

Added in version 1.4 of package punct-lib.

The Typst renderer class. Extends punct-abstract-render% to produce Typst markup output. You can extend this class to customize Typst rendering behavior.

Added in version 1.4 of package punct-lib.

5.5.4 Plain text🔗

 (require punct/render/plaintext) package: punct-lib

Sometimes you want to convert a document into a text format that is even plainer than Markdown, such as when generating the plaintext version of an email newsletter.

procedure

(doc->plaintext pdoc line-width [fallback]) → string?

  pdoc : document?
  line-width : exact-nonnegative-integer?
  fallback : 
(-> symbol?
    (listof (list/c symbol? string?))
    (listof xexpr?)
    xexpr?)
   = (make-plaintext-fallback line-width)
Renders pdoc into a string of plain text, hard-wrapped to line-width characters (except for block-quotes, which are hard-wrapped to a length approximately 75% as long as line-width). Any custom elements are passed to fallback, which must return a string.

The function applies very rudimentary text formatting which usually looks as you would expect, but which often discards information.

  • Level 1 headings are underlined with =, and all other headings are underlined with -.

  • Link destination URLs are given inside parentheses directly following the link text.

  • Code blocks are indented with four spaces, and the language name, if any, is discarded.

  • Images are replaced with their "alt" text, prefixed by "Image: " and wrapped in parentheses; the source URL and title are discarded.

For more information on using the fallback argument to render custom elements, see Rendering custom elements.

Examples:
> (require punct/render/plaintext)
> (define email (parse-markup-elements (hasheq) '("# Issue No. 1\n\nHowdy!")))
> (display (doc->plaintext email 72))

Issue No. 1

===========

Howdy!

Returns a function that accepts three arguments (the tag, attributes and elements of an X-expression). Mainly used to create the default fallback procedure for doc->plaintext.

Examples:
> (define foo (make-plaintext-fallback 72))
> (foo 'kbd '() '("Enter"))

"[kbd] Enter\n\n"

> (foo 'a '((href "http://example.com")) '("Link"))

"[a] Link\n\n"

5.5.5 Base renderer🔗

 (require punct/render/base) package: punct-lib

class

punct-abstract-render% : class?

  superclass: object%

The abstract base class for all Punct renderers. To create a custom renderer, extend this class and implement all abstract methods. The built-in HTML, Typst, and plaintext renderers all extend this class.

constructor

(new punct-abstract-render% 
    [doc doc] 
    [render-fallback render-fallback]) 
 → (is-a?/c punct-abstract-render%)
  doc : document?
  render-fallback : 
(-> symbol?
    (listof (list/c symbol? string?))
    list?
    any/c)
Creates a new renderer instance. The doc argument is the Punct document to render. The render-fallback procedure is called for any custom elements encountered during rendering.

method

(send a-punct-abstract-render render-document) → any/c

The main entry point for rendering. Calls the appropriate rendering methods for each element in the document body and footnotes.

The default implementation returns two values: a list of rendered body elements and a list of rendered footnotes. Subclasses typically override this to combine these into a single output value (e.g., a string or X-expression).

method

(send a-punct-abstract-render render-string s) → any/c

  s : string?
Called for every string in the document. Override this to transform raw text (e.g., for escaping special characters in the target format). The default implementation returns the string unchanged.A

Added in version 1.4 of package punct-lib.

To create a custom renderer, extend this class and implement all of the abstract methods below.

See Extending the Renderer for examples of extending the base renderer.

method

(send a-punct-abstract-render render-thematic-break) → any/c

method

(send a-punct-abstract-render render-heading level 
  rendered-elems) 
 → any/c
  level : string?
  rendered-elems : list?

method

(send a-punct-abstract-render render-code-block info-string 
  raw-elems) 
 → any/c
  info-string : string?
  raw-elems : list?

method

(send a-punct-abstract-render render-html-block raw-content)

 → any/c
  raw-content : any/c

method

(send a-punct-abstract-render render-paragraph rendered-elems)

 → any/c
  rendered-elems : list?

method

(send a-punct-abstract-render render-blockquote rendered-elems)

 → any/c
  rendered-elems : list?

method

(send a-punct-abstract-render render-itemization 
  style 
  start 
  rendered-items) 
 → any/c
  style : string?
  start : string?
  rendered-items : list?

method

(send a-punct-abstract-render render-item rendered-elems)

 → any/c
  rendered-elems : list?

method

(send a-punct-abstract-render render-line-break) → any/c

method

(send a-punct-abstract-render render-bold rendered-elems)

 → any/c
  rendered-elems : list?

method

(send a-punct-abstract-render render-italic rendered-elems)

 → any/c
  rendered-elems : list?

method

(send a-punct-abstract-render render-code raw-elems) → any/c

  raw-elems : list?

method

(send a-punct-abstract-render render-link dest 
  title 
  rendered-elems) 
 → any/c
  dest : string?
  title : string?
  rendered-elems : list?

method

(send a-punct-abstract-render render-image src    
  title    
  desc    
  raw-elems) → any/c
  src : string?
  title : string?
  desc : string?
  raw-elems : list?

method

(send a-punct-abstract-render render-html raw-content) → any/c

  raw-content : any/c

method

(send a-punct-abstract-render render-footnote-reference 
  label 
  defn-num 
  ref-num) 
 → any/c
  label : string?
  defn-num : string?
  ref-num : string?

method

(send a-punct-abstract-render render-footnote-definition 
  label 
  ref-count 
  rendered-elems) 
 → any/c
  label : string?
  ref-count : string?
  rendered-elems : list?