Views

Template Data And Helpers

Pass controller data to templates and use registered helper functions.

By Guillermo Alvarez - Published - Updated

Set template data

Controllers pass data to templates with Set:

func (c *PostsController) Show(
    _ http.ResponseWriter,
    r *http.Request,
) error {
    post, ok := c.posts.Get(r.PathValue("post_id"))
    if !ok {
        return lazycontroller.Error(http.StatusNotFound, fmt.Errorf("post not found"))
    }

    c.Set("title", post.Title)
    c.Set("post", post)
    return nil
}

The view reads those values by name:

<h1>{{.title}}</h1>
<article>{{.post.Body}}</article>

Use built-in helpers

lazyapp registers route, asset, form, and Turbo helpers:

<a href="{{path_for "posts"}}">Posts</a>
{{stylesheet "/styles.css"}}
{{importmap "/assets/importmap.json"}}

Helpers return ordinary strings or trusted fragments, depending on what the helper renders.

Register app helpers

Application helpers are passed to lazyapp.New:

func RegisterHelpers() map[string]any {
    return map[string]any{
        "read_time": ReadTime,
    }
}

Wire them during startup:

func App() *lazyapp.App {
    return lazyapp.New(lazyapp.Config{
        Name:    "sample_app",
        Drawer:  Draw,
        Public:  app.Public,
        Views:   app.Views,
        Dependencies: Dependencies,
        Helpers: lazyapp.Helpers{helpers.RegisterHelpers()},
    })
}

Then call the helper from a template:

<p>{{read_time .post.Body}} min read</p>

Add SEO metadata

lazyapp installs SEO helpers automatically. Configure application defaults with a context-aware SEO function, normally in init/seo.go, and wire it through lazyapp.Config.SEO:

func App() *lazyapp.App {
    return lazyapp.New(lazyapp.Config{
        Name:         "sample_app",
        Drawer:       Draw,
        Public:       app.Public,
        Views:        app.Views,
        Dependencies: Dependencies,
        SEO:          SEO,
    })
}
func SEO(ctx context.Context) []lazyseo.Option {
    return []lazyseo.Option{
        lazyseo.SiteName("GoLazy"),
        lazyseo.Description("A GoLazy application."),
        lazyseo.Language("en"),
        lazyseo.TwitterCardType("summary"),
    }
}

lazyapp.New calls Dependencies before SEO, so SEO defaults can read dependency-backed values from the app context.

Call {{seo_lang}} from the opening <html> tag and {{seo}} from the layout <head>:

<html lang="{{seo_lang}}">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    {{seo}}
  </head>
</html>

Read SEO And Sitemaps for controller metadata, structured data, robots.txt, and sitemap generation.

Use view variants

View variants are server-side template variants for the same route and format. They use the Rails-style +variant segment after the format:

app/views/posts/show.svg.tpl
app/views/posts/show.svg+square.tpl

Rendering show as svg with variant square tries the square template first and falls back to show.svg.tpl. Use this for generated image shapes such as a default social image and a square social image. These are not SEO alternates; SEO alternates are public URLs declared with c.Alternate(...).

Controllers can render that SVG content as a string:

svg, err := c.RenderSVGString("show", "square")
if err != nil {
    return err
}

That gives image-generation code a normal Go string to write, rasterize, or register as an asset before setting the public URL with c.SEOImage(...).