Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Custom Body Renderers

For a border or background, use container-func and keep the built-in renderer. To replace the marker/body layout, supply render-single. A small complete renderer uses two helpers. Pass the record supplied to the renderer; semantic deixis-query-notes records contain summaries, not live renderer data:

Source

#let card(note, ..args) = block(inset: 8pt, fill: gray.lighten(95%))[
  #deixis-generate-body-marker(note)
  #deixis-generate-body-content(note)
]
#deixis-inset-note(render-single: card)[A custom explanation.]

Complete source and preview setup

Output · Click to zoom

The connected card example adds a native reference and a connector to the body’s live start point. Ordinary note calls continue to use the built-in renderers without these helpers.

Destination And Content Have Separate Roles

deixis-generate-body-marker(note) publishes the native body destination and formats its marker. For a body without a visible marker, use deixis-generate-body-meta(note) instead. Emit one of these helpers once for that annotation. Calling both, repeating either, or duplicating a complete built-in renderer produces a duplicate-destination diagnostic. Render a separate annotation when it needs a second independently selectable body.

deixis-generate-body-content(note) returns note.body with live start/end metadata. It adds no marker, destination, container, styling, or backlink. Use it once where the body actually appears, rather than adding a second note.body. It is the same content path used by the built-in renderers. To transform the content inside a renderer, pass a copy with a replaced body:

Fragment · Requires surrounding code

#deixis-generate-body-content(note + (body: emph(note.body),))

Native layout supplies the locations, including continuations of a long inline, page-footnote, block-footnote, or endnote body. A span is not a rectangle. Framed connections still need a supported adapter and its actual single-frame evidence; use point: "start" or "end" for a content boundary.

What Each Renderer Supplies

The semantic catalogue always keeps registered declarations. Painting does not add another annotation or change the counter owner.

Renderer outputBody destination/native IDLive body span and page-note queriesBody connection
note.body aloneNoneNoneNo live endpoint
Body metadata/marker plus raw bodyPresentNoneNo complete span
Body-content helper aloneNonePresentMissing destination
Metadata/marker plus body-content helperPresentPresentStart/end points; complete frame when the adapter supports one

For a paired note without a body destination, deixis-ref and @id fall back to the original mark. Original/reused markers have no body link until one is published. A standalone body’s package reference displays ? and has no link when it lacks a destination; its page form also displays ?. A raw native link(id) needs an actual published native label.

Catalogue body.dest stays none when the renderer omits metadata. Its body.start/body.end can still exist when the content helper supplies a unique complete span. The catalogue row itself links to the original mark, or to a standalone body’s destination/declaration fallback. That declaration fallback is deliberately separate from a package reference’s live-body destination. deixis-query-notes(page: here().page()) selects complete spans, so a metadata-only renderer is absent from that page view. Queries never infer a painted body from a declaration or execute the renderer.

Custom output that duplicates or omits span boundaries cannot supply a unique catalogue span or connection point. Page queries exclude incomplete/duplicate/reversed spans, while the unfiltered catalogue retains their declarations. No geometry is guessed from marker text.

Measurement, Allocation, And Callbacks

Helpers honor note.disable-links: destinations and live span metadata are omitted during detached measurement, while the body keeps its native layout. Forward the original record so this flag survives. Do not render a second live copy to measure it. Callbacks should accept ..args; forward named arguments when delegating to a built-in renderer. Nested inline marks follow that detached sizing scope too: visible marker styling is retained, while their live destinations and body-link lookups are omitted. Their ordinary links remain in the actual rendered body. See scopes inside notes.

Margin bodies are measured in their declaration context at the selected frame width. A spilled body is measured again if that width changes. Keep a margin renderer’s size independent of the page it paints on (for example, do not scale it by here().page()): measurement and painting can otherwise disagree and packed bodies can overlap.

Page-footnote allocation is checked independently of these helpers. A custom renderer may omit its destination/span or return empty content without being mistaken for a missing native entry. See rendering.

For return links, add deixis-generate-backlinks(note) at the intended location, or delegate to a built-in renderer to retain its policy and formatting. A custom renderer owns its own container, marker arrangement, and backlink composition. The default grid group stacks a series when any note uses a custom single renderer. With only default aligned single renderers, it paints cells directly and bypasses containers. Inline-decoration bodies retain their own formatting path; see configuration.

Explicit deixis-generate-backlinks(note) generates the available buttons even when note.backlink is false. The built-in renderer decides whether to invoke it according to that policy. A custom renderer owns that choice; the helper itself does not add another destination or live span.