Skip to content

Component Model

Create a component by calling its package’s constructor, then render it in a templ template or through its Render method. Each constructor returns a Go value that implements templ.Component.

Configure a component

Each package defines its own configuration. Most constructors accept a config struct; Button, Link, Kbd, and Tooltip use option functions. The examples below create a badge and a submit button.

Configuration structs

Set the fields you need in the component’s config struct.

Badge configuration
badge.Badge(badge.Config{
    Label:      "Requires attention",
    Tone:       badge.ToneDanger,
    Appearance: badge.AppearanceSoft,
    Size:       badge.SizeSM,
})

Functional options

Pass option functions to set individual properties.

Button options
button.Button(
    button.WithTone(button.TonePrimary),
    button.WithSize(button.SizeSmall),
    button.WithType("submit"),
)

Render a component

Use templ’s @ syntax to include a component in a template. Components that accept child content, such as Button, render the content inside the following block.

Save button in a templ file
package views

import "github.com/araihu/goshtoso/components/button"

templ SaveButton() {
    @button.Button(button.WithType("submit")) {
        Save changes
    }
}

From a Go handler, call SaveButton().Render(r.Context(), w) and handle the returned error. The template supplies the button’s label; the component supplies its markup and behavior.

Use a shared interface

Use templ.Component when a function only needs to render a component. Goshtoso also defines components.Component, which adds Kind() to identify the component type.

Public interface
type Component interface {
    templ.Component
    Kind() Kind
}

Every public Goshtoso component implements this interface, so []components.Component can hold buttons, tables, dialogs, and other component types.

Keep the concrete type when needed

A constructor returns a concrete type, such as button.Instance or table.Instance. Keep that type when you need its additional methods. Assigning the value to an interface lets you share rendering code, but only the interface’s methods are available through that variable.

Concrete and common types
saveButton := button.Button(button.WithType("submit"))

var component components.Component = saveButton
var renderable templ.Component = saveButton

Identify a component

Call Kind() when logging or other shared code needs to distinguish component types. For example, this function counts tables in a collection.

Count tables in a collection
func countTables(items []components.Component) int {
    count := 0
    for _, item := range items {
        if item.Kind() == components.KindTable {
            count++
        }
    }
    return count
}

Kind values use stable kebab-case names, such as table and alert-dialog. Compare them with the constants in the components package.

Defaults and API reference

Leaving a field unset may select a component default. Check the component’s examples for the rendered result and its Go API reference for the meaning of each field, option, and method.

For examples, compare the Button API and Table API.