Documentation
¶
Index ¶
- Constants
- func Cached(ttl time.Duration, factory func() templ.Component) func() templ.Component
- func CachedByKey[K comparable](ttl time.Duration, factory func(K) templ.Component) func(K) templ.Component
- func CachedPartial(ttl time.Duration, keyFn func(context.Context) string, ...) func(Context) Result
- func Chain(mws ...func(http.Handler) http.Handler) func(http.Handler) http.Handler
- func Flash(ctx Context, level, message string)
- func FlashError(ctx Context, message string)
- func FlashInfo(ctx Context, message string)
- func FlashSuccess(ctx Context, message string)
- func FlashWarning(ctx Context, message string)
- func New(routes ...Route) http.Handler
- func Scope(prefix string) func(string) string
- func SetAuth[T any](ctx context.Context, auth T) context.Context
- type CachedOption
- type Context
- type DecodeError
- type DecodeErrorKind
- type EventStream
- type FlashMessage
- type FlashOOBRenderer
- type Layout
- type LocationOptions
- type OOBSwap
- type Result
- type Route
- func Delete[Q, I any](path string, handler func(Context, Q, I) Result) Route
- func Get[Q any](path string, handler func(Context, Q) Result) Route
- func HandleInternalError(comp func(Context) templ.Component) Route
- func HandleNotFound(comp func(Context) templ.Component) Route
- func Patch[Q, I any](path string, handler func(Context, Q, I) Result) Route
- func Post[Q, I any](path string, handler func(Context, Q, I) Result) Route
- func Put[Q, I any](path string, handler func(Context, Q, I) Result) Route
- func SSE[Q any](path string, handler func(ctx Context, query Q, stream EventStream)) Route
- func Static(prefix string, fsys fs.FS) Route
- func WS[Q any](path string, handler func(ctx Context, query Q, conn *WSConn), ...) Route
- type Router
- type Routes
- type StatusBuilder
- type WSConn
- func (c *WSConn) Close(reason string) error
- func (c *WSConn) Conn() *websocket.Conn
- func (c *WSConn) ReadHTMX(ctx context.Context) (WSRequest, error)
- func (c *WSConn) ReadJSON(ctx context.Context, v any) error
- func (c *WSConn) ReadText(ctx context.Context) (string, error)
- func (c *WSConn) Write(ctx context.Context, msg string) error
- func (c *WSConn) WriteHTMX(ctx context.Context, msg WSMessage) error
- func (c *WSConn) WriteJSON(ctx context.Context, v any) error
- type WSMessage
- type WSRequest
Constants ¶
const ( SwapInnerHTML = "innerHTML" SwapOuterHTML = "outerHTML" SwapBeforeBegin = "beforebegin" SwapAfterBegin = "afterbegin" SwapBeforeEnd = "beforeend" SwapAfterEnd = "afterend" SwapDelete = "delete" SwapNone = "none" SwapInnerMorph = "innerMorph" SwapOuterMorph = "outerMorph" SwapTextContent = "textContent" )
Swap strategies for HX-Reswap / hx-swap.
Variables ¶
This section is empty.
Functions ¶
func Cached ¶
Cached wraps a templ component factory with time-based caching. The factory is called once and the resulting component is reused for the given duration. After expiry, the next call re-invokes the factory. The component is rendered with the actual request context each time, so thx.ViewContext and layouts work correctly.
var sidebar = thx.Cached(5*time.Minute, func() templ.Component {
return sidebarTemplate(loadNavItems())
})
Use in a handler: thx.Render(ctx, sidebar())
func CachedByKey ¶
func CachedByKey[K comparable](ttl time.Duration, factory func(K) templ.Component) func(K) templ.Component
CachedByKey wraps a keyed templ component factory with per-key caching. Each unique key gets its own cached component with the given TTL. Expired entries are evicted on cache miss.
var userCard = thx.CachedByKey[string](time.Minute, func(userID string) templ.Component {
return userCardTemplate(loadUser(userID))
})
Use in a handler: thx.Render(ctx, userCard("user-123"))
func CachedPartial ¶
func CachedPartial( ttl time.Duration, keyFn func(context.Context) string, factory func(context.Context) (templ.Component, error), opts ...CachedOption, ) func(Context) Result
CachedPartial caches the rendered bytes of a partial, keyed by a request-derived key (e.g. locale), and refreshes them every ttl.
Unlike Cached, the factory receives a context, so it can load data on a cache miss, and it may return an error — which is surfaced to the caller (HTTP 500) and never cached. That context carries the request's values but is detached from its cancellation, so an aborted fetch (navigation, reload, HTMX swap) cannot cancel a build the whole TTL window — and every other caller waiting on the same flight — depends on. It is bounded by its own timeout instead; see WithBuildTimeout. Output is cached as bytes rather than as a component, so consumers that bind their locale at view-context construction stay correct as long as the key includes the locale.
A cache hit within ttl serves the cached bytes directly. On a miss or once an entry is stale, the factory is re-rendered synchronously, single-flighted across concurrent callers so a burst triggers one render they all share. If a re-render fails but stale bytes are still held, the stale bytes are served (availability over freshness); a cold render error is surfaced to the caller (HTTP 500) and never cached. The component is rendered without layouts, like Partial.
var greeting = thx.CachedPartial(time.Minute,
func(ctx context.Context) string { return view.Lang(ctx) },
func(ctx context.Context) (templ.Component, error) {
data, err := api.FetchGreeting(ctx)
if err != nil {
return nil, err
}
return greetingView(data), nil
},
thx.WithCacheControl(),
)
// Use in a handler:
func (c *Controller) getGreeting(ctx thx.Context, _ struct{}) thx.Result {
return greeting(ctx)
}
func Chain ¶
Chain composes multiple middleware into a single middleware. Middleware are applied in the order given: the first middleware in the list is the outermost wrapper.
func Flash ¶
Flash stores a flash message that will be available on the next request. Typically called before a redirect. Common levels: "success", "error", "info", "warning". Messages are truncated to 200 runes and at most 5 messages are stored per redirect. Stored in an HttpOnly cookie.
func FlashError ¶
FlashError is a shorthand for Flash(ctx, "error", message).
func FlashSuccess ¶
FlashSuccess is a shorthand for Flash(ctx, "success", message).
func FlashWarning ¶
FlashWarning is a shorthand for Flash(ctx, "warning", message).
func New ¶
New creates an http.Handler from the given routes. It builds an http.ServeMux, applies all routes, and wraps the result with any top-level middleware and not-found handling.
func Scope ¶
Scope generates an identifier specific to the current execution context. It uses the current stack trace to create a unique identifier, which is then base64 encoded and prefixed with the provided string. This is useful for generating unique ids for elements in a web application.
Note: Make sure to store the result in a package variable, as it is expensive to compute.
Types ¶
type CachedOption ¶
type CachedOption func(*cachedConfig)
CachedOption configures CachedPartial.
func WithBuildTimeout ¶ added in v0.2.0
func WithBuildTimeout(timeout time.Duration) CachedOption
WithBuildTimeout overrides how long a detached build may run before its context is cancelled. Defaults to 30 seconds. A non-positive duration leaves the default in place.
func WithCacheControl ¶
func WithCacheControl() CachedOption
WithCacheControl makes CachedPartial emit a "Cache-Control: private, max-age=<ttl>" response header, letting the client cache the fragment for the same duration the server does.
type Context ¶
Context is the request-scoped context passed to all handlers. It extends context.Context with HTTP helpers for cookies, headers, path params, HTMX integration, redirects, and layout control.
func ViewContext ¶
ViewContext retrieves the thx Context from a standard context.Context. Use this inside templ components to access request-scoped helpers like HTMX(), Param(), or Cookie(). Panics if called outside a thx request.
type DecodeError ¶
type DecodeError struct {
Kind DecodeErrorKind
Key string
Err error
}
DecodeError is the error returned by form and query decoding. Kind separates client mistakes (ErrUnknownKey, ErrMalformedValue, ErrLimitExceeded) from programming mistakes (ErrInvalidTarget), and Key names the offending input.
func (*DecodeError) Error ¶
func (e *DecodeError) Error() string
func (*DecodeError) Is ¶
func (e *DecodeError) Is(target error) bool
Is matches a DecodeError against its kind, so errors.Is(err, ErrUnknownKey) works without unwrapping to a *DecodeError first.
func (*DecodeError) Unwrap ¶
func (e *DecodeError) Unwrap() error
type DecodeErrorKind ¶
type DecodeErrorKind string
DecodeErrorKind classifies why decoding failed. It is itself an error, so a kind can be matched with errors.Is:
if errors.Is(err, thx.ErrUnknownKey) { /* client sent a key we don't know */ }
const ( // ErrUnknownKey means the key does not address any field of the target // struct. Only returned for form bodies; query strings ignore extra keys. ErrUnknownKey DecodeErrorKind = "unknown key" // ErrMalformedValue means the key addressed a field, but the submitted // value could not be converted to that field's type. ErrMalformedValue DecodeErrorKind = "malformed value" // ErrLimitExceeded means the key exceeded a decoder limit: too many path // segments, or an index beyond what a client may address. ErrLimitExceeded DecodeErrorKind = "limit exceeded" // ErrInvalidTarget means the decode destination itself is wrong — a bug in // the handler's type parameters, not in the request. ErrInvalidTarget DecodeErrorKind = "invalid target" )
func (DecodeErrorKind) Error ¶
func (k DecodeErrorKind) Error() string
type EventStream ¶
type EventStream interface {
// Send writes a data-only SSE message.
Send(data string) error
// SendEvent writes an SSE message with a named event type.
SendEvent(event string, data string) error
// SendJSON marshals data as JSON and sends it as an SSE data field.
SendJSON(data any) error
}
EventStream provides methods for sending Server-Sent Events to the client.
type FlashMessage ¶
FlashMessage is a one-time message that survives a redirect.
func Flashes ¶
func Flashes(ctx Context) []FlashMessage
Flashes reads and clears all flash messages. Returns nil if there are none. The cookie is deleted after reading. Subsequent calls in the same request return nil — flashes are consumed exactly once.
type FlashOOBRenderer ¶
type FlashOOBRenderer func([]FlashMessage) templ.Component
FlashOOBRenderer turns pending flash messages into a component that is appended to HTMX responses as an out-of-band swap.
type Layout ¶
Layout wraps a templ component with surrounding markup (e.g. a page shell). Layouts nest innermost-first: the first layout in the slice wraps the component directly, and each subsequent layout wraps the previous result.
type LocationOptions ¶
type LocationOptions = internal.LocationOptions
LocationOptions configures a client-side HTMX navigation via HX-Location.
type OOBSwap ¶
type OOBSwap struct {
// contains filtered or unexported fields
}
OOBSwap represents an out-of-band swap targeting a specific element.
type Result ¶
Result is the return type of all route handlers. It writes the handler's output to the HTTP response.
func JSON ¶
JSON returns a Result that serializes data as JSON with the appropriate Content-Type header.
func Partial ¶
Partial returns a Result that renders the component without any layouts. Useful for returning HTML fragments for HTMX partial updates.
type Route ¶
type Route interface {
Apply(*Router)
}
Route is the building block for defining HTTP routes. Implementations register themselves on a Router via Apply.
func Delete ¶
Delete registers a DELETE route at the given path. Q is the query parameter type and I is the request body input type.
func Get ¶
Get registers a GET route at the given path. Q is the query parameter type. The handler receives the decoded query parameters and returns a Result.
func HandleInternalError ¶
HandleInternalError registers a custom error page rendered when a handler panics or returns an error. The component receives the request context.
func HandleNotFound ¶
HandleNotFound registers a custom 404 page rendered with the given component. The component receives the request context so it can access path values, HTMX state, etc.
func Patch ¶
Patch registers a PATCH route at the given path. Q is the query parameter type and I is the request body input type.
func Post ¶
Post registers a POST route at the given path. Q is the query parameter type and I is the request body input type (form or JSON).
func Put ¶
Put registers a PUT route at the given path. Q is the query parameter type and I is the request body input type.
func SSE ¶
func SSE[Q any](path string, handler func(ctx Context, query Q, stream EventStream)) Route
SSE registers a Server-Sent Events route at the given path. The handler receives an EventStream for pushing events to the client. The connection stays open until the handler returns or the client disconnects.
func Static ¶
Static serves static files from the given filesystem at the given URL prefix. Files requested with a "v" query parameter get immutable cache headers (1 year, immutable). Files without it get standard caching (no-cache).
func WS ¶
func WS[Q any](path string, handler func(ctx Context, query Q, conn *WSConn), acceptOpts ...*websocket.AcceptOptions) Route
WS registers a WebSocket route at the given path. The handler receives a WSConn for bidirectional communication. Optional AcceptOptions configure the WebSocket upgrade; by default, origin checking is skipped.
type Router ¶
type Router struct {
// Mux is the underlying ServeMux. Exposed for direct handler registration.
Mux *http.ServeMux
// contains filtered or unexported fields
}
Router holds the routing state accumulated while applying routes. It wraps a standard http.ServeMux and tracks layouts, middleware, and error handlers for the current scope.
type Routes ¶
type Routes []Route
Routes is an ordered collection of Route values that applies as a group.
func WithFlashOOB ¶
func WithFlashOOB(selector string, strategy string, render FlashOOBRenderer, routes ...Route) Routes
WithFlashOOB makes pending flash messages render automatically on every HTML response of the given routes, without calling SwapOOB by hand. The selector and strategy are passed through to OOBWithStrategy, and the renderer produces the markup — thx dictates no container or toast markup.
thx.WithFlashOOB("#flashes", thx.SwapAfterBegin, toasts,
thx.Get("/dashboard", dashboard),
)
Only HTMX requests are touched (history restores excluded, since HTMX ignores OOB swaps there). On those requests the OOB swap owns the flashes: they are consumed before the primary component renders, so a layout calling Flashes gets nil. Responses that are not rendered HTML — redirects, JSON, raw — leave the flash cookie intact for the next page load.
func WithLayout ¶
WithLayout wraps all given routes with an additional layout. The new layout becomes the innermost wrapper, closest to the rendered component. Layouts from parent scopes remain outermost.
func WithMiddleware ¶
WithMiddleware wraps the given routes with an HTTP middleware. The middleware sees the original request before any route-level processing.
type StatusBuilder ¶
type StatusBuilder struct {
// contains filtered or unexported fields
}
StatusBuilder constructs results with a specific HTTP status code.
func Status ¶
func Status(code int) *StatusBuilder
Status begins building a Result with a custom HTTP status code. Chain with Render, JSON, Raw, or Empty to complete the result.
return thx.Status(http.StatusCreated).JSON(user)
func (*StatusBuilder) Empty ¶
func (s *StatusBuilder) Empty() Result
Empty returns a Result that writes only the configured status code with no body.
func (*StatusBuilder) JSON ¶
func (s *StatusBuilder) JSON(data any) Result
JSON returns a Result that serializes data as JSON with the configured status code.
func (*StatusBuilder) Raw ¶
func (s *StatusBuilder) Raw(val string) Result
Raw returns a Result that writes the string as plain text with the configured status code.
type WSConn ¶
type WSConn struct {
// contains filtered or unexported fields
}
WSConn wraps a WebSocket connection with convenience methods for text, JSON, and HTMX message exchange.
func (*WSConn) Close ¶
Close gracefully closes the WebSocket connection with a normal closure status.
type WSMessage ¶
type WSMessage struct {
Channel string `json:"channel,omitempty"`
Format string `json:"format,omitempty"`
Target string `json:"target,omitempty"`
Swap string `json:"swap,omitempty"`
Payload string `json:"payload"`
}
WSMessage is the HTMX 4.0 WebSocket response envelope sent to the client.
type WSRequest ¶
type WSRequest struct {
Type string `json:"type"`
RequestID string `json:"request_id"`
Event string `json:"event"`
Path string `json:"path"`
Headers map[string]any `json:"headers"`
Values map[string]any `json:"values"`
}
WSRequest is the HTMX 4.0 WebSocket request envelope sent by the client.