Skip to content

Overriding Introduction

Overriding allows you to override how Iridium resolves your components inside it's rendering pipeline.

We recommend giving the Varients section a quick read before progressing.

Varients

A varient is just the term Iridium uses to describe the state of a component at different points in it's rendering journey. There are three typical varients.

  • Resolvable
  • Concrete
  • View

Resolvable

A resolvable is the entry point to a host of Iridium's components. It's a representation of some state that needs to be resolved at runtime.

A FormInput field on your form is a typical example of a resolvable component. You can provide static state like a label through it's Label method, or a callback function (LabelFn) that can use the current request context to determine the state of the label

go
// static 
FormInput("name").
    Label("Your Name")

// callback
FormInput("name").
    LabelFn(
        func (ctx FieldContext) string {
            // You can access the current request context through the 
            // ctx field here to set your label dynamically 
            if ctx.Request.URL.Path == "/admin/users/create" {
                return "Label is on user's create page"
            }
            return "Your Name"
        }
    )

Behind the scenese, both Label and LabelFn set the same value, either as a callback or static value

go
type InputResolvable[T any] struct {
    LabelStr util.Resolvable[*context.FieldContext[T], string]
}

You can see we defined a resolvable LabelStr field here. util.Resolvable can contain a callback that returns a string when provided that *context.FieldContext[T] struct, or simply a static string.

Are a FormInput and InputResolvable[T] different?

No, a FormInput is a alias for InputResolvable[T] you receive through type generation.

Type generation docs are here

Converting a Resolvable To a Concrete

Once you're finished defining your form for example

Iridium can now take your form definition, and when a user performs a request for your form, can generate that FieldContext struct for you, passes it to your resolvable component, to produce a static form of your input called a concrete input.

Generating context and defining how a resolvable is converted to it's concrete form is an overridable process that you can learn more about here.

Concrete Varients

Concrete varients represent the state of your component after it has resolved all its state based on the current request.

go
type InputConcrete struct {
    LabelStr string
}

You can see now we have a finalized form of that LabelStr.

TIP

Concrete varients can live on their own. In fact, in custom pages, you can call on them directly to borrow our components and place them in your custom pages.

You can learn about re-using our components in your own custom pages here

Passing a Concrete Varient to a View Varient

Concrete varients register which view (or templ.Component) will be produced from their state in a callback function.

This is where most users will spend time overriding Iridium's defaults. Dedicated docs

Example

Here's how you might bind the concrete varient of an input to a templ.Component so that some HTML can be rendered out whenever an Input is created

go
bootstrap.RegisterNamedView[components.InputConcrete](
		views.Input, // <- a simple constant to identify a view. Allows for multiple views per component
        func(u components.InputConcrete) (templ.Component, error) {
            // Here you are passed your concrete input varient whenever one is generated
            // Now you can choose which templ.Component to return.

            // You can choose any templ.Component here, allowing you to override Iridium's default view
            // and provide your own.

		},
	)

View Varient

The view varient is simple to understand. Generally view varients just embed their concrete forms and contain a Component method that returns the final templ.Component for rendering.

Released under the MIT License.