On this pageNew / OptionsRuntime Metrics (expvars)Structured Logging (slog)Register / Has / ComponentsValidateAllRenderPageRenderFragmentString helpersDeprecated context aliasesRenderWithCollectorServeComponentServePageComponentMountWithDataMiddlewareRegisterFuncRegisterDirectiveMissing prop handlingComponentErrorHandlerParseFile / ComponentRendererRegistryDirective interfaceDirectiveBinding / ContextDirectiveRegistryDirectiveWithContentStyleCollectorScopeID / ScopeCSSError typesSentinel errorsCompileToTemplateRegisterTemplateTemplateText

Go API Reference

Complete reference for every exported symbol in the htmlc package. Import path: github.com/dhamidi/htmlc.

Creating an Engine

New

func New(opts Options) (*Engine, error)

Creates an Engine from opts. If opts.ComponentDir is set the directory is walked recursively and all *.vue files are registered before the engine is returned.

engine, err := htmlc.New(htmlc.Options{
    ComponentDir: "./components",
})
if err != nil {
    log.Fatal(err)
}

Options

type Options struct {
    ComponentDir string
    Reload       bool
    FS           fs.FS
    Directives   DirectiveRegistry
    Debug        bool
    Logger       *slog.Logger
}
FieldDescription
ComponentDirDirectory walked recursively for *.vue files. Each file is registered by its base name without extension (Button.vueButton). When two files share the same base name the last one in lexical order wins.
ReloadWhen true the engine checks the modification time of every registered file before each render and re-parses changed files automatically. Use during development; leave false in production.
FSWhen set, all file reads and directory walks use this fs.FS instead of the OS filesystem. ComponentDir is interpreted as a path within the FS. Useful with //go:embed. Hot-reload requires the FS to also implement fs.StatFS.
DirectivesCustom directives available to all components rendered by this engine. Keys are directive names without the v- prefix. Built-in directives cannot be overridden.
DebugWhen true the rendered HTML is annotated with HTML comments describing component boundaries, expression values, and slot contents. Development use only.

Runtime Metrics (expvars)

PublishExpvars

func (e *Engine) PublishExpvars(prefix string) *Engine

Registers the engine's metrics in the global expvar registry under prefix. After calling this method all counters and configuration state are visible at the /debug/vars HTTP endpoint as a JSON object keyed by prefix. Returns the engine for method chaining.

Internally this creates a top-level *expvar.Map via expvar.NewMap(prefix). It panics if called twice with the same prefix — the same semantics as expvar.NewMap. Call it exactly once per engine per process, immediately after creating the engine.

engine, err := htmlc.New(htmlc.Options{ComponentDir: "./components"})
if err != nil {
    log.Fatal(err)
}
engine.PublishExpvars("myapp") // registers metrics under "myapp" key

Exposed variables

All variables appear as children of the prefix map in the /debug/vars JSON output:

KeyTypeDescription
reloadexpvar.Int (0/1)Whether hot-reload is enabled.
debugexpvar.Int (0/1)Whether debug mode is enabled.
componentDirexpvar.StringCurrent component directory path.
fsexpvar.StringType name of the current fs.FS, or "<nil>" when no custom FS is set.
rendersexpvar.IntCumulative number of successful render calls.
renderErrorsexpvar.IntCumulative number of failed render calls.
reloadsexpvar.IntCumulative number of hot-reload scans performed.
renderNanosexpvar.IntCumulative render time in nanoseconds.
componentsexpvar.Func → IntNumber of currently registered components (computed on each read).
info.directivesexpvar.Func → ArraySorted list of registered custom directive names (computed on each read).

Setter methods

These methods update both the live engine option and the corresponding expvar immediately. They are usable whether or not PublishExpvars has been called.

SetDebug

func (e *Engine) SetDebug(enabled bool)

Enables or disables debug mode. When enabled is true, rendered HTML is annotated with comments describing component boundaries, expression values, and slot contents. Updates the debug expvar to 1 or 0 immediately.

SetReload

func (e *Engine) SetReload(enabled bool)

Enables or disables hot-reload. When enabled is true, the engine stats every registered component file before each render and re-parses any that have changed. Updates the reload expvar to 1 or 0 immediately.

SetComponentDir

func (e *Engine) SetComponentDir(dir string) error

Changes the component directory to dir, walks the new directory recursively, and rebuilds the component registry. Returns an error if the directory cannot be walked. Updates the componentDir expvar to the new path immediately.

SetFS

func (e *Engine) SetFS(fsys fs.FS) error

Replaces the engine's filesystem with fsys, then rebuilds the component registry by walking the current ComponentDir inside the new FS. Returns an error if the directory walk fails. Updates the fs expvar to the type name of fsys (or "<nil>") immediately.

Integration note: The /debug/vars handler is registered on http.DefaultServeMux automatically when the expvar package is imported. For a custom *http.ServeMux, register it explicitly:

import "expvar"

mux.Handle("GET /debug/vars", expvar.Handler())

Structured Logging (slog)

Options.Logger

type Options struct {
    // ...
    Logger *slog.Logger
}
DetailValue
Type*slog.Logger
Defaultnil (no logging)
Effect when nilA single pointer-nil check is performed per render; no allocations, no timing, behaviour identical to before structured logging was added.
Effect when non-nilOne structured log record is emitted for every component in the render tree. Records include component name, render duration, bytes written, and (on failure) the error.
Minimum Go version:log/slog was added in Go 1.21. Passing a non-nil Logger requires Go 1.21 or later.

Log record specification

Every rendered component emits one record. The attributes are:

Attribute keyslog typeValue
componentslog.StringResolved component name (e.g. NavBar)
durationslog.DurationWall-clock time for the component subtree. Text handlers format this as 1.2ms; JSON handlers emit it as nanoseconds (int64).
bytesslog.Int64Bytes written by the component subtree.
errorslog.AnyNon-nil only on LevelError records for failed renders.

Example text-handler output:

time=2026-03-16T12:00:00.001Z level=DEBUG msg="component rendered" component=NavLink duration=1.2ms bytes=142
time=2026-03-16T12:00:00.002Z level=DEBUG msg="component rendered" component=NavBar duration=4.5ms bytes=612
time=2026-03-16T12:00:00.149Z level=DEBUG msg="component rendered" component=HomePage duration=148.6ms bytes=24576

Example JSON-handler output (note: duration is nanoseconds as int64):

{"time":"2026-03-16T12:00:00.001Z","level":"DEBUG","msg":"component rendered","component":"NavLink","duration":1200000,"bytes":142}
{"time":"2026-03-16T12:00:00.149Z","level":"DEBUG","msg":"component rendered","component":"HomePage","duration":148600000,"bytes":24576}

Log levels

  • Successful render — emitted at slog.LevelDebug with message htmlc.MsgComponentRendered.
  • Failed render — emitted at slog.LevelError with message htmlc.MsgComponentFailed, plus a non-nil error attribute.

Constants

const MsgComponentRendered = "component rendered"
const MsgComponentFailed   = "component render failed"

These constants are the stable message strings used in every log record. Reference them in log-based test assertions or alerting rules so that a future rename is caught at compile time rather than by a broken alert:

// Log assertion in a test:
if record.Message != htmlc.MsgComponentRendered {
    t.Errorf("unexpected message: %q", record.Message)
}

Renderer.WithLogger

func (r *Renderer) WithLogger(l *slog.Logger) *Renderer

Attaches l to the renderer. Use this when working with the low-level Renderer API directly — for example, to attach a request-scoped logger enriched with logger.With("request_id", id) to a per-request renderer. Returns r for method chaining.

renderer := htmlc.NewRenderer(component).
    WithComponents(reg).
    WithLogger(logger.With("request_id", requestID))

Record ordering

Records are emitted in leaf-first (post-order) order because the log call fires after the entire component subtree finishes rendering. The root page component is always the last record. This is useful for identifying which child component is the bottleneck: the first record with a high duration is where time is actually spent.

Performance

When Options.Logger is nil (the default), a single pointer-nil check is the only overhead per component. No timing, no allocations — behaviour is identical to before structured logging was added. Logging costs are incurred only when a non-nil logger is supplied.

Rendering

RenderPage

func (e *Engine) RenderPage(ctx context.Context, w io.Writer, pageName string, data map[string]any) error

Renders the named component as a full HTML page and writes the result to w. Scoped styles are collected from the entire component tree and injected as a <style> block immediately before the first </head> tag. If no </head> is found the style block is prepended to the output. The render is aborted and ctx.Err() is returned if the context is cancelled or its deadline is exceeded.

Use RenderPage for page components that include <!DOCTYPE html>, <html>, <head>, and <body>.

var buf bytes.Buffer
err := engine.RenderPage(ctx, &buf, "HomePage", map[string]any{
    "title": "Welcome",
})

RenderFragment

func (e *Engine) RenderFragment(w io.Writer, name string, data map[string]any) error

Renders the named component as an HTML fragment and prepends the collected <style> block to the output. Does not search for a </head> tag. Use for partial page updates such as HTMX responses or turbo-frame updates.

String helpers

func (e *Engine) RenderPageString(ctx context.Context, name string, data map[string]any) (string, error)
func (e *Engine) RenderFragmentString(ctx context.Context, name string, data map[string]any) (string, error)

Convenience wrappers around RenderPage and RenderFragment that return the result as a string instead of writing to an io.Writer.

Deprecated context aliases

// Deprecated: Use RenderPage, which now accepts a context.Context directly.
func (e *Engine) RenderPageContext(ctx context.Context, w io.Writer, name string, data map[string]any) error
// Deprecated: Use RenderFragment, which now accepts a context.Context directly.
func (e *Engine) RenderFragmentContext(ctx context.Context, w io.Writer, name string, data map[string]any) error

RenderPageContext and RenderFragmentContext are deprecated aliases kept for backwards compatibility. RenderPage and RenderFragment now accept a context.Context directly as their first argument; use those instead.

RenderWithCollector

func (e *Engine) RenderWithCollector(ctx context.Context, name string, props map[string]any, collector *CustomElementCollector) (string, error)

Low-level render method that uses a caller-supplied CustomElementCollector. Most callers should use RenderPage or RenderFragment instead; those methods manage the collector lifecycle automatically. Use RenderWithCollector only when you need to control the collector lifecycle yourself — for example, when aggregating custom-element registrations across multiple renders before emitting scripts.

HTTP Integration

ServeComponent

func (e *Engine) ServeComponent(name string, data func(*http.Request) map[string]any) http.HandlerFunc

Returns an http.HandlerFunc that renders name as a fragment on every request. The data function is called per-request to build the template scope; it may be nil. Data middleware registered via WithDataMiddleware is applied after the data function. Sets Content-Type: text/html; charset=utf-8.

mux.HandleFunc("GET /search-results", engine.ServeComponent("SearchResults", func(r *http.Request) map[string]any {
    return map[string]any{"query": r.URL.Query().Get("q")}
}))

ServePageComponent

func (e *Engine) ServePageComponent(name string, data func(*http.Request) (map[string]any, int)) http.HandlerFunc

Returns an http.HandlerFunc that renders name as a full HTML page. The data function returns both the template scope and the HTTP status code to send. A status code of 0 is treated as 200. If data is nil a 200 OK response with no template data is used.

mux.HandleFunc("GET /post/{id}", engine.ServePageComponent("PostPage", func(r *http.Request) (map[string]any, int) {
    post, err := db.GetPost(r.PathValue("id"))
    if err != nil {
        return map[string]any{"error": err.Error()}, http.StatusNotFound
    }
    return map[string]any{"post": post}, http.StatusOK
}))

Mount

func (e *Engine) Mount(mux *http.ServeMux, routes map[string]string)

Registers multiple component routes on mux at once. Keys are http.ServeMux patterns (e.g. "GET /{$}", "GET /about"); values are component names. Each component is served as a full page via ServePageComponent with no data function.

engine.Mount(mux, map[string]string{
    "GET /{$}":    "HomePage",
    "GET /about":  "AboutPage",
    "GET /blog":   "BlogPage",
})

WithDataMiddleware

func (e *Engine) WithDataMiddleware(fn func(*http.Request, map[string]any) map[string]any) *Engine

Adds a function that augments the data map on every HTTP-triggered render. Multiple middleware functions are called in registration order; later middleware can overwrite keys set by earlier ones. Returns the engine for chaining.

Data middleware applies only to the top-level render scope and is not automatically propagated into child component scopes. Pass shared values via RegisterFunc if child components need them.

engine.WithDataMiddleware(func(r *http.Request, data map[string]any) map[string]any {
    data["currentUser"] = userFromRequest(r)
    data["csrfToken"]   = csrf.Token(r)
    return data
})

Component Management

Register

func (e *Engine) Register(name, path string) error

Manually adds a component from path to the engine's registry under name, without requiring a directory scan. Useful for programmatically generated components or files outside ComponentDir.

Has

func (e *Engine) Has(name string) bool

Reports whether name is a registered component.

Components

func (e *Engine) Components() []string

Returns the names of all registered components in sorted order. Automatic lowercase aliases added by the engine are excluded.

ValidateAll

func (e *Engine) ValidateAll() []ValidationError

Checks every registered component for unresolvable child component references. Returns one ValidationError per problem; an empty slice means all components are valid. Call once at application startup to surface missing-component issues early.

if errs := engine.ValidateAll(); len(errs) != 0 {
    for _, e := range errs {
        log.Println(e)
    }
    os.Exit(1)
}

Customization

RegisterFunc

func (e *Engine) RegisterFunc(name string, fn func(...any) (any, error)) *Engine

Adds a per-engine function available in all template expressions. The function is callable from templates as name(). Engine functions have lower priority than user-provided data keys. They are propagated automatically into every child component's scope. For behaviour attached to a Go type already in the render scope, exported methods are callable directly from expressions without registration — see Calling methods on scope values in the Concepts guide.

engine.RegisterFunc("formatDate", func(args ...any) (any, error) {
    t, ok := args[0].(time.Time)
    if !ok {
        return "", fmt.Errorf("formatDate: expected time.Time")
    }
    return t.Format("Jan 2, 2006"), nil
})

RegisterDirective

func (e *Engine) RegisterDirective(name string, dir Directive)

Adds a custom directive under name (without the v- prefix). Replaces any previously registered directive with the same name. Panics if dir is nil.

engine.RegisterDirective("tooltip", &TooltipDirective{})

WithMissingPropHandler

func (e *Engine) WithMissingPropHandler(fn MissingPropFunc) *Engine

Sets the function called when any component has a missing prop. The default behaviour renders a visible [missing: <name>] placeholder. Use ErrorOnMissingProp for strict error behaviour or SubstituteMissingProp for legacy placeholder text.

// Abort rendering on any missing prop
engine.WithMissingPropHandler(htmlc.ErrorOnMissingProp)

// Substitute a legacy placeholder string
engine.WithMissingPropHandler(htmlc.SubstituteMissingProp)

ComponentErrorHandler / HTMLErrorHandler

type ComponentErrorHandler func(w io.Writer, path []string, err error) error

func HTMLErrorHandler() ComponentErrorHandler

ComponentErrorHandler is a function called when a child component fails to render. It receives the output writer, the component path (breadcrumb of component names from root to the failing component), and the error. It may write fallback HTML to w. If it returns a non-nil error, rendering is aborted; returning nil allows rendering to continue.

HTMLErrorHandler returns a built-in ComponentErrorHandler that writes an HTML comment describing the error and continues rendering, making component failures visible in the output without aborting the page.

renderer := htmlc.NewRenderer(component).
    WithComponents(reg).
    WithComponentErrorHandler(htmlc.HTMLErrorHandler())

Low-level API

ParseFile

func ParseFile(path, src string) (*Component, error)

Parses a .vue Single File Component from the string src. path is used only for error messages and the scope attribute hash. Returns a *Component whose Template field is a parsed HTML node tree. Only the top-level <template> and <style> sections are extracted; <template> is required. A <script> or <script setup> block causes ParseFile to return a parse error immediately.

Component

type Component struct {
    Template *html.Node // root of the parsed template node tree
    Script   string     // always empty; <script> blocks are rejected by ParseFile
    Style    string     // raw <style> content (empty if absent)
    Scoped   bool       // true when <style scoped> was present
    Path     string     // source file path passed to ParseFile
    Source   string     // raw source text (for error location reporting)
    Warnings []string   // non-fatal issues found during parsing
}

Holds the parsed representation of a .vue Single File Component. The Warnings field may contain notices about auto-corrected self-closing component tags.

Component.Props

func (c *Component) Props() []PropInfo

Walks the template AST and returns all top-level variable references the template uses. Identifiers starting with $ and v-for loop variables are excluded.

type PropInfo struct {
    Name        string   // identifier name
    Expressions []string // template expressions in which it appears
}

Registry

type Registry map[string]*Component

Maps component names to their parsed components. Keys may be PascalCase or kebab-case. Most callers use Engine, which builds and maintains a Registry automatically.

Renderer

func NewRenderer(c *Component) *Renderer

Creates a Renderer for c. Use the builder methods below to configure it before calling Render.

Renderer is the low-level rendering primitive. Most callers should use Engine via RenderPage or RenderFragment. Use NewRenderer when you need fine-grained control over style collection or registry attachment.

Builder methodDescription
WithStyles(sc *StyleCollector) *RendererSets the StyleCollector that receives this component's style contribution.
WithComponents(reg Registry) *RendererAttaches a component registry, enabling component composition.
WithMissingPropHandler(fn MissingPropFunc) *RendererSets the handler called when a template prop is absent from the scope.
WithDirectives(dr DirectiveRegistry) *RendererAttaches a custom directive registry.
WithContext(ctx context.Context) *RendererAttaches a context.Context; the render is aborted on cancellation.
WithFuncs(funcs map[string]any) *RendererAttaches engine-registered functions so they are available in expressions and propagated to all child renderers.
WithCollector(c *CustomElementCollector) *RendererSets the CustomElementCollector used to accumulate custom-element registrations during rendering.
WithComponentErrorHandler(h ComponentErrorHandler) *RendererSets the handler called when a child component fails to render. See ComponentErrorHandler.
WithComponentPath(path []string) *RendererSets the component path (breadcrumb) passed to ComponentErrorHandler calls for nested components.
WithNSComponents(ns map[string]map[string]*Component, componentDir string) *RendererAttaches a namespace-keyed component registry for multi-namespace component resolution.

Renderer.Render / RenderString

func (r *Renderer) Render(w io.Writer, scope map[string]any) error
func (r *Renderer) RenderString(scope map[string]any) (string, error)

Evaluates the component's template against scope and writes HTML to w (or returns it as a string). Prop validation and style collection happen here.

Package-level helpers

func Render(w io.Writer, c *Component, scope map[string]any) error
func RenderString(c *Component, scope map[string]any) (string, error)

Convenience wrappers that create a temporary Renderer for c. They do not collect styles or support component composition. Use NewRenderer with WithStyles and WithComponents when those features are needed.

Directives

Directive interface

type Directive interface {
    Created(node *html.Node, binding DirectiveBinding, ctx DirectiveContext) error
    Mounted(w io.Writer, node *html.Node, binding DirectiveBinding, ctx DirectiveContext) error
}

Implemented by custom directive types. Register with Engine.RegisterDirective or pass in Options.Directives. Only the Created and Mounted hooks are called because htmlc renders server-side.

  • Created — called before the element is rendered. Receives a shallow-cloned working node whose Attr slice and Data field may be freely mutated. Return a non-nil error to abort rendering.
  • Mounted — called after the element's closing tag has been written to w. Bytes written to w appear immediately after the element. Return a non-nil error to abort rendering.

DirectiveBinding / DirectiveContext

type DirectiveBinding struct {
    Value     any             // result of evaluating the directive expression
    RawExpr   string          // un-evaluated expression string from the template
    Arg       string          // directive argument after the colon, e.g. "href" in v-bind:href
    Modifiers map[string]bool // dot-separated modifiers, e.g. {"prevent": true}
}
type DirectiveContext struct {
    Registry          Registry // component registry the renderer is using
    RenderedChildHTML string   // fully rendered inner HTML of the host element; empty for void elements
}

RenderedChildHTML contains the fully rendered children of the directive's host element — all template expressions evaluated, child components expanded — before either hook runs. It is available in both Created and Mounted. Use it to inspect or transform the rendered subtree, for example in a syntax-highlighting directive that needs the source text after expression evaluation.

DirectiveRegistry

type DirectiveRegistry map[string]Directive

Maps directive names (without the v- prefix) to their implementations. Keys are lower-kebab-case; the renderer normalises names before lookup.

DirectiveWithContent

type DirectiveWithContent interface {
    Directive
    InnerHTML() (html string, ok bool)
}

Optional extension of Directive. When a directive's Created hook wants to replace the element's children with custom HTML, implement this interface. The renderer calls InnerHTML after Created returns; if it returns a non-empty string, the element's template children are skipped and the returned HTML is written verbatim between the opening and closing tags (equivalent to v-html on the element itself). Return ("", false) to fall back to normal child rendering.

// Example: a directive that wraps children in a callout box
type CalloutDirective struct {
    renderedHTML string
}

func (d *CalloutDirective) Created(node *html.Node, b htmlc.DirectiveBinding, ctx htmlc.DirectiveContext) error {
    d.renderedHTML = ctx.RenderedChildHTML
    return nil
}

func (d *CalloutDirective) Mounted(w io.Writer, node *html.Node, b htmlc.DirectiveBinding, ctx htmlc.DirectiveContext) error {
    return nil
}

func (d *CalloutDirective) InnerHTML() (string, bool) {
    h := d.renderedHTML
    d.renderedHTML = ""
    if h == "" {
        return "", false
    }
    return `<div class="callout">` + h + `</div>`, true
}

Style Collection

StyleCollector

type StyleCollector struct { /* unexported fields */ }

Accumulates StyleContribution values from one or more component renders into a single ordered list, deduplicating contributions from the same scoped component. Engine creates and manages a StyleCollector automatically on each render call.

func (sc *StyleCollector) Add(c StyleContribution)
func (sc *StyleCollector) All() []StyleContribution
  • Add — appends c, skipping duplicates. Two contributions are duplicates when they share the same composite key (ScopeID + CSS).
  • All — returns all contributions in the order they were added.

StyleContribution

type StyleContribution struct {
    ScopeID string // scope attribute name (e.g. "data-v-a1b2c3d4"), empty for global styles
    CSS     string // stylesheet text, already rewritten by ScopeCSS for scoped components
}

ScopeID / ScopeCSS

func ScopeID(path string) string
func ScopeCSS(css, scopeAttr string) string
  • ScopeID — returns "data-v-" followed by 8 hex digits derived from the FNV-1a 32-bit hash of path.
  • ScopeCSS — rewrites css so that every selector in every non-@-rule has scopeAttr appended to its last compound selector. @-rules are passed through verbatim.

Error Handling

Error types

ParseError

type ParseError struct {
    Path     string          // source file path
    Msg      string          // human-readable description
    Location *SourceLocation // source position, or nil if unknown
}

Returned by ParseFile when a .vue file cannot be parsed.

RenderError

type RenderError struct {
    Component string          // component name being rendered
    Expr      string          // expression that triggered the error (may be empty)
    Wrapped   error           // underlying error
    Location  *SourceLocation // source position, or nil if unknown
}

Returned by render methods when template evaluation fails. Implements Unwrap.

ValidationError

type ValidationError struct {
    Component string // name of the component with the problem
    Message   string // description of the problem
}

One entry per problem in the slice returned by ValidateAll.

SourceLocation

type SourceLocation struct {
    File    string // source file path
    Line    int    // 1-based line number (0 = unknown)
    Column  int    // 1-based column (0 = unknown)
    Snippet string // ~3-line context around the error (may be empty)
}

ConversionError

type ConversionError struct {
    Component string          // component being converted
    Directive string          // directive involved (may be empty)
    Message   string          // human-readable description
    Location  *SourceLocation // source position, or nil if unknown
    Cause     error           // underlying error (may be nil)
}

var ErrConversion

Returned by CompileToTemplate and RegisterTemplate when a component cannot be converted to an html/template-compatible representation. errors.Is(err, htmlc.ErrConversion) is true for all conversion failures.

MissingPropFunc / handlers

type MissingPropFunc func(name string) (any, error)

func ErrorOnMissingProp(name string) (any, error)
func SubstituteMissingProp(name string) (any, error)
  • MissingPropFunc — signature for missing-prop handlers; receive the prop name, return a substitute value or an error.
  • ErrorOnMissingProp — aborts rendering with an error whenever a prop is absent. Use for strict validation.
  • SubstituteMissingProp — returns "MISSING PROP: <name>" as a placeholder string.

Sentinel errors

var ErrComponentNotFound = errors.New("htmlc: component not found")
var ErrMissingProp       = errors.New("htmlc: missing required prop")
var ErrConversion        // sentinel for html/template conversion errors
  • ErrComponentNotFound — wrapped inside the error returned by render methods when the requested component name is not registered.
  • ErrMissingProp — returned (wrapped) when a required prop is absent and no MissingPropFunc has been set.
  • ErrConversion — sentinel for ConversionError values returned by CompileToTemplate and RegisterTemplate.
if errors.Is(err, htmlc.ErrComponentNotFound) {
    http.NotFound(w, r)
    return
}

html/template Interop

These methods allow components to be used with Go's standard html/template package — either by compiling htmlc components into *html/template.Template values, or by registering existing Go templates as components.

CompileToTemplate

func (e *Engine) CompileToTemplate(componentName string) (*html/template.Template, error)

Compiles the named component to a *html/template.Template. Returns a ConversionError (sentinel: ErrConversion) if the component uses features that cannot be expressed in Go's template language.

RegisterTemplate

func (e *Engine) RegisterTemplate(name string, tmpl *html/template.Template) error

Registers an existing *html/template.Template as an htmlc component under name. Other components may then use <Name></Name> to embed it. Returns a ConversionError if the template cannot be adapted.

TemplateText

func (e *Engine) TemplateText(componentName string) (text string, warnings []string, err error)

Returns the html/template-compatible template source text for the named component, along with any non-fatal warnings produced during conversion. Useful for inspecting the generated template text or for integrating with other template engines.

text, warnings, err := engine.TemplateText("NavBar")
if err != nil {
    log.Fatal(err)
}
for _, w := range warnings {
    log.Println("warning:", w)
}
fmt.Println(text)