Skip to content

Overriding Views

Overriding allows you to supplant our registered resolvers in our bootstrap registry for how we generate context, convert resolvable varients to concrete varianets, and finally how we pick a view for our concrete varients.

Rendering Pipeline Notes

You don't have to understand how we resolve components to templ components to start overriding. If you need to override a view quickly you can just to this section here

If you need more information on how this works, which is recommended when overriding resolvable & context factories, it's recommended you first read about how the pipeline & bootstrapping works. This all sounds more complicated than it actually is.

Overriding a View

You're able to override the view templ component for a varitey of Iridium's content. You first need to identify what you'll be overriding. Please see our section here for what views you can override.

Default Registration

To better understand how overrides work, take a look at Iridium's default Input view binding.

go
// default/fields.go
import (
    "github.com/a-h/templ"
    "github.com/iridiumgo/iridium/bootstrap/views"
    viewFields "github.com/iridiumgo/iridium/view/components/fields"
)

// this is run for you when launching Iridium.
bootstrap.RegisterNamedView[components.InputConcrete](
		views.Input, func(u components.InputConcrete) (templ.Component, error) {
            return viewFields.NewInput(u).Component(), nil
		},
	)

and here would be it's (simplified) view component it calls to with viewFields.NewInput(u)

go
// Most view structs just embed their concrete form and have a `Component` method to 
// get the actual templ.Component for rendering.
type Input struct {
    components.InputConcrete
}

// We pass in a concrete form generally to setup our view
// struct with the info required to render out all the options.
func NewInput(u components.InputConcrete) {
    return Input{
        InputConcrete: u,
    }
}

// Massively simplified templ function. The actual HTML does not
// matter for the purposes of this exercise however
templ (i *Input) Component() {
    <input id={i.Key}/>
}
Explanation

When you define a FormInput on a form, you're interacting with it's resolvable varient when you call methods like Label or LabelFn etc. It's called a resolvable because those callbacks you write need to be resolved at runtime based on the current request.

When Iridium begins to resolve all your form components, it first generates a context struct based on the current request, and then passes that to your resolvable component to produce a concrete varient. This concrete varient defines the final options for your input based on the current request.

Iridium then takes that concrete varient, and searches for which view component belongs to it. Above, you see we bound a InputConcrete to the Input struct in our view file via that RegisterNamedView callback.

Each time you create a concrete input it will run that callback to produce the final templ.Component that is then rendered

INFO

Since you can define just the final concrete to view binding, you can let Iridium handle creating a context based on the current request and producing a concrete form. You are then free to use that concrete form for your own view component, or not to use it, or to add or remove fields! It only expects a final templ.Component - it doesn't care what that templ.Component actually is.

View Override Example

Lets say you need greater control over how inputs are rendered out as part of Iridium.

Somewhere in your

you can write a function to call our bootstrap and override our input view.

Creating a custom templ component

You'll want to create a new .templ file where you can create a custom component:

go
// my_custom_input.templ
package views


templ Input() {
    // Put anything you want in here.
    // Doesn't even need to be an input. Could be nothing,
    // or a ton of custom HTML & scripting.
    <p>Hey I override your input with this message!</p>
}

TIP

Make sure after generating your new templ component, you run templ generate in your terminal to be able to use it!

Registering your new component

You can now bind your custom templ component to the concrete input component. That way, whenever a concrete input is produced, your callback not Iridium's will run.

go
// overrides.go
package overrides
import (
	"github.com/a-h/templ"

	"github.com/iridiumgo/iridium/bootstrap"
	"github.com/iridiumgo/iridium/bootstrap/views"
	"github.com/iridiumgo/iridium/core/field/components"

    // Your own directory where you created your templ component.
    // This is not apart of the Iridium library
    "views/overrides" 
)

func OverrideIridiumButton() {
    bootstrap.RegisterNamedView[components.InputConcrete](
		views.Input, func(u components.InputConcrete) (templ.Component, error) {
            return overrides.Input(), nil
		},
	)
}

Finishing Up

That's basically all you need to override Iridium's Input component.

FAQ

  • Can I use a Go template instead?
    • At the bootstrapping level everything is understood via templ.Component. So no, but:
    • Templ integrates with go templates! See here
  • Does this have to override everything? Can i choose?
    • In your callback method you can include if statements and still call out to our original components if you want!

View Component List

Pages

ConstName
PagePanelBasepage::view:panel:base
PagePanelFormpage::view:panel:form
PagePanelTablepage::view:panel:table

Forms

ConstName
FormViewBaseform::view:base
ConstName
NavBarnav::view:bar
NavLinkGroupnav::view:link-group
NavLinknav::view:link
NavHeadernav::view:header
NavSideBarFooternav::view:side:footer
NavTopBarFooternav::view🔝footer

Table

ConstName
TableViewBasetable::view:base
TableViewDatatable::view:data
TableViewRowtable::view:row

Widgets

ConstName
StatWidgetwidget::view:stat
ChartWidgetwidget::view:chart
TableWidgetwidget::view:table

Fields

ConstName
Buttonfield::view:button
Inputfield::view:input
Radiofield::view:radio
Rangefield::view:range
Selectfield::view:select
Switchfield::view:switch
DateTimePickerfield::view:datetime-picker
TextAreafield::view:textarea

Layout

ConstName
Gridlayout::view:grid
Sectionlayout::view:section
Tabslayout::view:tabs
Tablayout::view:tab

Actions

ConstName
ActionViewaction::view:base

Error Pages

ConstName
ErrorViewerror::view:base
ErrorNotFoundViewerror::view:not-found
ErrorInternalServerErrorViewerror::view:internal-server-error
ErrorForbiddenPageViewerror::view:forbidden
ErrorUnauthorizedViewerror::view:unauthorized
ErrorBadRequestViewerror::view:bad-request
ErrorServiceUnavailableViewerror::view:service-unavailable

Released under the MIT License.