Help us shape the future of Go! Take the 2026 Go Developer Survey

render

package
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package render wraps go-partial: a layout with a content slot and optional out-of-band regions, served as a full page or as an HTMX fragment.

Index

Constants

This section is empty.

Variables

View Source
var ErrReserved = errors.New("template function name is a go-partial helper")

ErrReserved is returned for a template function named like a go-partial helper; see Reserved.

View Source
var ErrShown = errors.New("render error answered")

ErrShown wraps the error Render returns after an error stage answered the request, such as the development error page (see Diagnostics.Development) or an error template (Diagnostics.ErrorPage), with status 500 and never cached: callers log it and write nothing more.

Functions

func Reserved

func Reserved(name string) bool

Reserved reports whether name is one the templates' own helpers use: go-partial's (content, url, request, …, or a name starting with "_") and those of the stages every renderer installs (locale, localizer, slot, hasSlot, requiredSlot, deferredSlot, targetHeader, targetValue and targetIs). Functions with these names would never be called.

Types

type Diagnostics

type Diagnostics struct {
	// Development shows a failing template in detail, with the template and
	// line, on go-partial's ext/errors error page, and makes
	// {{debug .}} show a value (ext/debug). Never in production: there a
	// failing render writes nothing and its caller answers a plain error,
	// unless the renderer has error templates (ErrorPage, ErrorFragment).
	Development bool
	// ErrorPage is a template that answers, outside development, a request
	// whose page failed, such as a theme's 500.gohtml, with status 500 and
	// never cached (go-partial's ext/errors WithTemplate). It renders on its
	// own, without the layout, as a child of the part that failed, with its
	// functions, the view's includes and models; its dot is an ext/errors
	// Data, whose Error it must not show (Data.Detailed is false; its
	// Message is a safe sentence, see ErrorMessage). ErrorFragment is the
	// same for a partial request, such as an HTMX navigation, in the place
	// of the part requested. When only one of them is set, it answers both.
	// When an error template fails itself, go-partial's own error markup
	// answers, without the error's details.
	ErrorPage     string
	ErrorFragment string
	// ErrorFlash, when set, answers a partial request that failed to render,
	// outside development, with an error message of the renderer's exp/flash
	// stage (see Renderer.Use) instead of ErrorFragment: added to the flash
	// target out of band, with the text ErrorFlash returns for the request,
	// leaving the request's own target as it is (go-partial's ext/errors
	// WithFlash). The response keeps status 500, so with HTMX 4 the
	// page lets 5xx responses swap their out-of-band parts only (the
	// clientAttrs "keepOnServerError" setting).
	ErrorFlash func(r *http.Request) string
	// ErrorMessage, when set, returns the text of the safe sentence
	// message (go-partial's ext/errors SafeMessage) for the request, such as
	// its translation in the request's language: the Message of the error
	// templates' Data, also the text of the error flash message when
	// ErrorFlash returns none (go-partial's ext/errors WithMessage). An
	// empty text keeps the sentence.
	ErrorMessage func(r *http.Request, message string) string
	// ErrorTitle, when set, returns the text of the title, the status text
	// of the error (http.StatusText), for the request, such as its
	// translation in the request's language: the heading of go-partial's
	// built-in error page, and the Title of the error templates' Data
	// (go-partial's ext/errors WithTitle). An empty text keeps the status
	// text.
	ErrorTitle func(r *http.Request, title string) string
	// ErrorLanguage, when set, returns the language of the error page for
	// the request, such as the language of the page that failed: the lang
	// attribute of go-partial's built-in error page, and the Lang of the
	// error templates' Data (go-partial's ext/errors WithLang).
	ErrorLanguage func(r *http.Request) string
	// Logger receives go-partial's warnings, such as a function it ignored;
	// nil uses slog.Default at the time of each warning. Errors are returned
	// by Render instead.
	Logger *slog.Logger
	// Stages run in every render, around the templates of the layout, the
	// content and every region, for example go-partial's exp/metrics.
	Stages []partial.RenderStage
	// Events receive go-partial's diagnostic events, for example exp/otel's
	// sink, which adds them to the request's trace span.
	Events []partial.EventSink
}

Diagnostics configures what a renderer reports about its renders.

type Fragment

type Fragment struct {
	ID       string
	Template string
	// Data is the fragment's dot, on the page and on its own.
	Data any
	// Dot, when set, replaces Data, such as a dot computed only when the
	// fragment renders (partial.DotFuncOf): only a request for the fragment
	// pays for its data. A Dot of a known type is checked against the
	// fragment's @dot before it is computed.
	Dot partial.Dot
	// Deferred fragments load after the page, such as a panel whose data is
	// expensive: on the page, {{slot "ID"}} places a placeholder that asks
	// for the fragment from the page's own address as soon as the page
	// loads (go-partial's slots.Deferred), so the page itself never
	// computes the fragment's dot. The default placeholder is an empty
	// element with the fragment's ID. Placeholder, a template of the view's
	// file system, defers the fragment with a placeholder of the site's own,
	// whose dot is a go-partial slots.PlaceholderData and whose outer
	// element carries its ID and Attrs; it has the view's includes.
	Deferred    bool
	Placeholder string
	// PlaceholderData is the placeholder's PlaceholderData.Data, such as
	// the heading of a panel, so one placeholder template serves several
	// fragments (go-partial's slots.Data).
	PlaceholderData any
}

Fragment is a part of a page that HTMX can ask for on its own, by the ID of its element, such as a comment thread that a form updates or a list that loads when it scrolls into view. On a full page the layout or a content template places it with {{slot "ID"}}, or with {{requiredSlot "ID"}}, which fails when the page has no such fragment; a request whose target is the ID gets only the fragment, rendered from the same template with the same dot, or with the regions out of band for a view with FragmentRegions. The template's outer element carries the ID.

Fragments are go-partial exp/slots slots that answer requests on their own: a request for a fragment is answered with the fragment alone when the page has what the fragment declares (slots.CheckContracts): data of its @dot type, and a value for every @model among the view's models. A page without, such as the one a form's action returned to after the form's own page, answers with its content instead, as a navigation (see Renderer.Render).

type Region

type Region struct {
	ID       string
	Template string
	Files    fs.FS
	Data     any
	// Dot, when set, replaces Data, such as a dot computed only when the
	// region renders; see View.Dot.
	Dot partial.Dot
}

Region is an independently rendered part of the layout.

type Renderer

type Renderer struct {
	// contains filtered or unexported fields
}

Renderer renders views in one layout. Templates are parsed once and kept, the layout as well as the content templates, unless SetReload asks to read them again for every render.

func New

func New(files fs.FS, layout string, funcs ...template.FuncMap) *Renderer

New creates a renderer for a layout template using the HTMX 4 protocol. Functions whose first parameter is a context.Context receive the context of the render, as go-partial binds them; templates call them without it. A later map replaces the functions of earlier ones, also a function without a context replacing one with.

Names of go-partial's own helpers and of the stages the renderer installs (see Reserved) cannot be replaced: go-partial ignores such functions, or its stages replace them, with a warning in the log.

A renderer without a layout ("") only renders parts on their own; see RenderPartial.

func (*Renderer) CheckTemplates

func (r *Renderer) CheckTemplates() ([]partial.TemplateProblem, error)

CheckTemplates parses every *.gohtml file of the renderer's file system with the functions and stages its renders have, and reports every problem a render would fail with: a file that does not parse, a function the renderer does not have, a {{template}} no file defines (go-partial's Partial.CheckTemplates). Of an Overlay, each problem names the layer that serves the file. The error is that of reading the files.

func (*Renderer) Connector

func (r *Renderer) Connector() connector.Connector

Connector is the renderer's go-partial connector (HTMX 4), for handlers that inspect a request or answer one with connector.IsRequest, connector.CurrentURL or a connector.ResponseBuilder.

func (*Renderer) FailureStages

func (r *Renderer) FailureStages() []partial.RenderStage

FailureStages are the stages a partial below the renderer's root adds for an error that happened outside a render, answered with go-partial's ext/errors Respond, such as a visitor's post that failed to save, or a render that failed without an error template: outside development, for a renderer without error templates, go-partial's built-in error page without the error's details, with the texts of Diagnostics.ErrorMessage and ErrorTitle and the language of Diagnostics.ErrorLanguage. A renderer with error templates, or in development, answers with its own error stage, and FailureStages is empty. Failing renders keep their answer: without error templates nothing is written, and the caller answers.

func (*Renderer) FirstExisting

func (r *Renderer) FirstExisting(candidates ...string) (string, error)

FirstExisting returns the first of candidates that is a template in the renderer's file system, such as a module screen of the theme before the module's default; see go-partial's Partial.FirstExisting. Without the template cache (see SetReload) the file system is asked every time; with it, the answer for each candidate is remembered, also when it is missing. Without a match the error wraps fs.ErrNotExist.

func (*Renderer) FirstExistingIn

func (r *Renderer) FirstExistingIn(layers []fs.FS, candidates ...string) (string, error)

FirstExistingIn returns the first of candidates found in layers, trying every candidate in a layer before the next one, such as a theme's templates before a module's defaults; see go-partial's Partial.FirstExistingIn. Without layers, those of the renderer's file system are used when it is a go-partial Overlay, such as a theme over the default theme. Answers are remembered as FirstExisting remembers them.

func (*Renderer) Funcs

func (r *Renderer) Funcs(funcs ...template.FuncMap)

Funcs adds template functions to every render, such as go-partial's exp/interactions functions, as New's funcs do. Call it before the first render.

func (*Renderer) HasEntry

func (r *Renderer) HasEntry(p *partial.Partial) (bool, error)

HasEntry reports whether the template of p defines the template p renders (go-partial's SetEntry and HasEntry), such as the "html" part of an e-mail, without rendering it: from the scan go-partial keeps with the renderer's template cache (see SetReload). p is made a part of the renderer, as RenderPartial does.

func (*Renderer) Render

func (r *Renderer) Render(w http.ResponseWriter, req *http.Request, view View) error

Render writes the view. When a template fails, in the layout or in the content (a parse or execution error, an unknown function, a missing partial, a failing component), nothing is written and the error is returned, so the caller answers it without showing internals to visitors. In development (see SetDiagnostics) go-partial's detailed error page is written instead, with status 500 and never cached, also for an HTMX request, and the error returned wraps ErrShown; so does the error after the error templates of Diagnostics answered the request.

An HTMX request receives only the content, or the region or fragment it targets. A request targeting another element, or a fragment this page cannot answer for (see Fragment), is a navigation: go-partial's target fallback answers it with the content, with HX-Retarget and HX-Reswap headers that swap it for the page's content element, and for a GET HX-Push-Url, so the address follows.

func (*Renderer) RenderPartial

func (r *Renderer) RenderPartial(
	ctx context.Context,
	req *http.Request,
	p *partial.Partial,
	models ...any,
) (template.HTML, error)

RenderPartial renders p on its own, as a part of the layout without the layout: with the renderer's functions, stages and diagnostics, its failure policy, and models for @model. Use it for parts such as components and the HTML part of e-mail (RenderText writes the text part); req may be nil outside a request. During a page render, pass the context the template function received, so the part shares the page's bound functions and a failing part fails the page.

p is made a part of the renderer (go-partial's SetParent), with its template cache (see SetReload), and given the models, so it is meant for one render: build a new one for the next.

func (*Renderer) RenderText

func (r *Renderer) RenderText(ctx context.Context, p *partial.Partial, models ...any) (string, error)

RenderText renders p as plain text, unescaped, with go-partial's RenderText, as RenderPartial renders HTML: with the renderer's functions, stages and template cache, and models for @model. Use it for text that is not HTML, such as the subject and the text part of an e-mail.

func (*Renderer) Respond

func (r *Renderer) Respond(w http.ResponseWriter, req *http.Request, status int, messages ...flash.Message) error

Respond answers a request that is refused rather than failed to render, such as one without permission, with messages and status, never cached (go-partial's flash.Respond): an HTMX request gets them as flash messages added to the page out of band, with the template and target of the renderer's exp/flash stage (see Use), leaving its own target as it is; any other request gets their texts as text/plain.

func (*Renderer) Root

func (r *Renderer) Root() *partial.Partial

Root is the partial every render of the renderer has as parent, with its file system, functions, stages, connector, template cache and diagnostics. A part that reaches the browser another way renders under it, such as a part of a page sent as a server-sent event with go-partial's exp/sse:

events := sse.NewWriter(w).SetParent(renderer.Root())
err := events.PatchPartial(r.Context(), r, "#viewers", partial.NewID("viewers", "viewers.gohtml").SetDot(view))

Render parts under it with SetParent, which leaves it as it is; configure the renderer with its own methods, before the first render.

func (*Renderer) SetDiagnostics

func (r *Renderer) SetDiagnostics(diagnostics Diagnostics)

SetDiagnostics sets what the renderer reports. Call it once, before the first render.

func (*Renderer) SetReload

func (r *Renderer) SetReload(reload bool)

SetReload makes the renderer read and parse its templates on every render when reload is true, so edits to template files show without a restart. Every partial rendered under the renderer follows it. It is meant for development; call it before the first render.

func (*Renderer) Use

func (r *Renderer) Use(stages ...partial.RenderStage)

Use adds render stages to every render, such as exp/flash's stage:

renderer.Use(flash.Stage())

Templates can call the functions the stages give them without a FuncMap. Call it before the first render.

type View

type View struct {
	// Template is the content template path.
	Template string
	// Includes are the templates the content, regions and fragments can
	// call, as fs.Glob patterns, such as "partials/*.gohtml" (go-partial's
	// SetChildIncludes on the page); the layout has none. The error
	// templates of Diagnostics get them too.
	Includes []string
	// Files overrides the renderer's file system for the content template.
	Files fs.FS
	// Data is the content template's dot; Shell is the layout's dot.
	Data  any
	Shell any
	// Dot and ShellDot, when set, replace Data and Shell with a go-partial
	// Dot, such as one computed only when the content or the layout renders
	// (partial.DotFuncOf), so a request for a fragment or region alone,
	// which leaves them out, costs nothing of theirs. A Dot given to several
	// parts of the page, such as the layout and its regions, is computed
	// once per response. An error fails the render.
	Dot      partial.Dot
	ShellDot partial.Dot
	// Models are the values templates can name with @model, matched by
	// type: the layout, the content and every partial, as go-partial's
	// SetModel does. A partial.ModelFuncOf is computed only when a template
	// calls it, once per response.
	Models []any
	// ContentID is the element ID HTMX swaps; "content" when empty.
	ContentID string
	// Status is the response status, also of a response for a region or a
	// fragment alone; zero is 200 OK. An error page keeps its own.
	Status int
	// Regions are layout parts updated alongside content, such as a header.
	// An HTMX response sends them out of band in this order, then those of
	// RegionFiles in the order of their file names, the same on every
	// render, so its bytes and ETag are too.
	Regions []Region
	// Fragments are parts of the page HTMX can ask for on their own by ID;
	// see Fragment.
	Fragments []Fragment
	// FragmentRegions sends the regions out of band with a fragment asked
	// for on its own, as with the content, rather than the fragment alone:
	// for a page whose fragments come from a new address, such as the
	// results of a live search that replaces the address while the visitor
	// types, so the head region's title and links and a language switch
	// follow it.
	FragmentRegions bool
	// RegionFiles and FragmentFiles add a region, with the layout's dot, or
	// a fragment, with the content's dot, for every template the fs.Glob
	// pattern finds in the renderer's file system, such as
	// "regions/*.gohtml": named after the file without its extension, such
	// as "menu" for regions/menu.gohtml (go-partial's slots.Glob). With the
	// template cache the files are found once; without (see SetReload), at
	// every render, so new files show.
	RegionFiles   string
	FragmentFiles string
	// RegionElements, by region name, are the IDs of the elements of a
	// region an HTMX request gets out of band instead of the whole region,
	// such as the menu items that change with a navigation (go-partial's
	// SetOOBElements): IDs that are not in the region's output are left
	// out, and when none of them is, the whole region goes. A full page is
	// not affected.
	RegionElements map[string][]string
	// RegionElementsFunc, by region name, chooses those IDs per request,
	// only when the region actually goes out of band (go-partial's
	// SetOOBElementsFunc), and names the request headers the choice
	// depends on, which the response's Vary header then lists. It replaces
	// RegionElements of the same region.
	RegionElementsFunc map[string]func(*http.Request) partial.OOBElements
	// HeadRegion names the region, of Regions or RegionFiles, that the
	// layout places in <head>, such as "head" for regions/head.gohtml
	// with the canonical, alternate and feed links of the page (go-partial's
	// exp/head): on a full page its elements sit between two empty
	// <template> markers, and out of band they replace the elements
	// between those markers, so the head keeps no element of the page
	// left. Its <title> goes on its own, which htmx sets as the document's
	// title.
	HeadRegion string
}

View is one response: a content template inside the layout.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL