component.mdin: /docs/internal/components/

We build a standard component to demo some things that you can do with things the library.

import (
	_ "embed"

	t ""

I don't know exactly why I feel like prefacing the name of the interface with I here, but given the overloading of component, I'm going to do it.

Each component is first and foremost a veun.AsView, and we attach behavior to it. For us the behavior is silly, we get metadata, a description.

type IComponent interface {
	Description() string

We also have a concrete view that we're creating from the interface.

func View(c IComponent) component {
	return component{
		Type:        fmt.Sprintf("%T", c),
		Description: c.Description(),
		Body:        c,

Our component uses the component.tpl in this directory.

//go:embed component.tpl
var tpl string
var componentTpl = t.MustParse("component", tpl)

type component struct {
	Type, Description string

	Body      veun.AsView
    BodyClass string

And the view that we create has an error handler based on the component itself.

func (v component) View(ctx context.Context) (*veun.View, error) {
	return veun.V(v.template()).WithErrorHandler(errorHandler{v}), nil

The template is reusable so that we can embed it into the errorView.

func (v component) template() t.Template {
	return t.Template{
		Tpl:   componentTpl,
		Slots: t.Slots{"body": v.Body},
		Data:  v,

many components

We can create our own components container, similar to veun.Views.

type Views []IComponent

func (v Views) View(ctx context.Context) (*veun.View, error) {
    items := make(veun.Views, len(v))
    for idx, c := range v {
        items[idx] = View(c)

    return items.View(ctx)