Generate type-safe URLs for your pages:
First, create a wrapper function for use in templ files:
// urlFor wraps structpages.URLFor for templ templates
func urlFor(ctx context.Context, page any, args ...any) (templ.SafeURL, error) {
url, err := structpages.URLFor(ctx, page, args...)
return templ.URL(url), err
}// Simple page references without parameters
<a href={ urlFor(ctx, index{}) }>Home</a>
<a href={ urlFor(ctx, product{}) }>Products</a>
<a href={ urlFor(ctx, team{}) }>Our Team</a>// Route definition
type pages struct {
userProfile `route:"/users/{id} User Profile"`
blogPost `route:"/blog/{year}/{month}/{slug} Blog Post"`
}
// In Go code (e.g., in handlers or middleware)
url, err := structpages.URLFor(ctx, userProfile{}, "123")
// Returns: /users/123// Single parameter - positional
<a href={ urlFor(ctx, userProfile{}, "123") }>View User</a>
// Multiple parameters - as key-value pairs
<a href={ urlFor(ctx, blogPost{}, "year", "2024", "month", "06", "slug", "my-post") }>
Read Post
</a>
// Using a map
<a href={ urlFor(ctx, blogPost{}, map[string]any{
"year": "2024",
"month": "06",
"slug": "my-post",
}) }>Read Post</a>Use the join helper to add query parameters:
// Helper function
func join(page any, pattern string) []any {
return []any{page, pattern}
}// Add query parameters with template placeholders
<a href={ urlFor(ctx, join(product{}, "?page={page}"), "page", "2") }>
Page 2
</a>
// Multiple query parameters
<form hx-post={ urlFor(ctx, join(toggle{}, "?redirect={url}"),
"id", todoId,
"url", currentURL) }>
<button>Toggle</button>
</form>
// Complex example with path and query parameters
<a href={ urlFor(ctx, join(jobDetail{}, "?tab={tab}"),
"id", jobId,
"tab", "overview") }>
Job Overview
</a>When calling URLFor within a handler, URL parameters from the current request are automatically available and will be used to fill matching parameters in the generated URL. This is particularly useful when generating URLs for related pages that share the same parameters.
// Route definitions
type pages struct {
viewProduct `route:"GET /product/{id} View Product"`
editProduct `route:"GET /product/{id}/edit Edit Product"`
}
// In the view handler
func (v viewProduct) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Generate edit URL - the {id} parameter is automatically extracted from current request
editURL, _ := structpages.URLFor(r.Context(), editProduct{})
// If current URL is /product/123, editURL will be "/product/123/edit"
// You can still override extracted parameters if needed
differentURL, _ := structpages.URLFor(r.Context(), editProduct{}, "456")
// differentURL will be "/product/456/edit"
}This feature works with multiple parameters as well:
type pages struct {
viewPost `route:"GET /blog/{year}/{month}/{slug} View Post"`
editPost `route:"GET /blog/{year}/{month}/{slug}/edit Edit Post"`
}
// In a template
templ (v viewPost) Page() {
// All parameters (year, month, slug) are automatically available
<a href={ urlFor(ctx, editPost{}) }>Edit this post</a>
// Override just one parameter while keeping others
<a href={ urlFor(ctx, viewPost{}, map[string]any{"slug": "different-post"}) }>
View different post in same month
</a>
}This automatic extraction eliminates the need to manually pass parameters that are already present in the current request context, making URL generation more convenient and less error-prone.
The ID and IDTarget functions generate consistent HTML IDs from component method references, helping maintain consistency between template IDs, HTMX targets, and component names.
When building HTMX applications, you often need to keep three things in sync:
- The ID attribute in your component template
- The HTMX target selector in your requests
- The component method name
// If you change "UserList" to "UserTable", you need to manually update:
<div id="user-list">...</div> // Manual ID
<button hx-target="#user-list">Refresh</button> // Manual target reference
templ (p TeamManagementView) UserList(users []User) { ... } // Component nameUse ID and IDTarget with method expressions to generate IDs automatically:
// In your component template - use ID() for HTML id attributes
templ (p TeamManagementView) UserList(users []User) {
<div id={ structpages.ID(ctx, p.UserList) }>
<!-- content -->
</div>
}
// In HTMX attributes - use IDTarget() for hx-target (includes "#" prefix)
templ (p TeamManagementView) Page(props Props) {
<button hx-get="/api/users"
hx-target={ structpages.IDTarget(ctx, p.UserList) }>
Refresh
</button>
<div id={ structpages.ID(ctx, p.UserList) }>
@p.UserList(props.Users)
</div>
}Now when you rename UserList to UserTable using your IDE's refactoring tools, all references including p.UserList will be automatically updated!
Both ID and IDTarget convert CamelCase/PascalCase to kebab-case:
ID(ctx, p.UserList)→"user-list"IDTarget(ctx, p.UserList)→"#user-list"ID(ctx, p.GroupMembers)→"group-members"ID(ctx, p.HTMLParser)→"html-parser"
The only difference is that IDTarget adds the "#" prefix for CSS selectors, while ID returns the raw ID string.
See the HTMX integration guide for more detailed examples and usage patterns.