ForgeUI is a comprehensive SSR-first UI framework for Go, built on templ with templui components, Tailwind CSS styling, and shadcn-inspired design patterns. It provides everything you need to build modern, interactive web applications entirely in Go.
- ✅ SSR-First: Pure Go component rendering with zero client-side dependencies required
- ✅ Type-Safe: Full Go type safety with templ templates
- ✅ templui Components: shadcn-inspired component library via templui
- ✅ Tailwind CSS: Utility-first CSS styling with built-in processing
- ✅ 35+ Components: Production-ready UI components
- ✅ Alpine.js Integration: Directives, stores, magic helpers, and plugins
- ✅ Client-Side Routing: Pinecone Router integration for SPA navigation
- ✅ HTMX Support: Complete HTMX attribute helpers and server-side utilities
- ✅ Icons: 1600+ Lucide icons with customization options
- ✅ Animation System: Tailwind animations, transitions, and keyframes
- ✅ Router: Production-ready HTTP routing with middleware support
- ✅ Bridge: Go-JavaScript RPC bridge for calling Go functions from client-side
- ✅ Plugin System: Extensible plugin architecture with dependency management
- ✅ Theme System: Customizable themes with CSS variables and color tokens
- ✅ Assets Pipeline: Built-in esbuild, Tailwind CSS, and file fingerprinting
- ✅ Dev Server: Hot-reload development server with file watching
- ✅ CLI: Command-line tools for project scaffolding and management
- ✅ Layout Helpers: Page builder with meta tags, scripts, and structured layouts
- 🚀 Go All The Way: Write your entire frontend in Go with templ templates
- 🎯 Type Safety: Catch errors at compile time, not runtime
- ⚡ SSR Performance: Server-rendered HTML with optional progressive enhancement
- 🎨 Beautiful by Default: shadcn-inspired design that looks great out of the box
- 🔧 Full Stack: Router, RPC, assets, themes - everything you need
- 📦 Zero Config: Works out of the box with sensible defaults
- 🔌 Extensible: Plugin system for adding custom functionality
- 🎭 Progressive: Start with pure SSR, add Alpine.js/HTMX as needed
go get github.com/xraph/forgeuimain.go:
package main
import (
"log"
"net/http"
"github.com/a-h/templ"
"github.com/xraph/forgeui"
"github.com/xraph/forgeui/router"
)
func main() {
// Create ForgeUI app
app := forgeui.New(
forgeui.WithDebug(true),
forgeui.WithThemeName("default"),
)
// Register routes
app.Get("/", HomePage)
// Start server
log.Println("Server running on http://localhost:8080")
http.ListenAndServe(":8080", app.Handler())
}
func HomePage(ctx *router.PageContext) (templ.Component, error) {
return HomePageView(), nil
}home.templ:
package main
templ HomePageView() {
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>ForgeUI App</title>
</head>
<body>
<div class="container mx-auto p-8">
<h1 class="text-4xl font-bold">Welcome to ForgeUI</h1>
<p>Build beautiful UIs with Go and templ.</p>
<a href="/about" class="btn btn-primary">Get Started</a>
</div>
</body>
</html>
}go run main.goVisit http://localhost:8080 to see your app!
Add Alpine.js for client-side interactivity in your .templ files:
package main
import "github.com/xraph/forgeui/alpine"
templ InteractivePage() {
<!DOCTYPE html>
<html lang="en">
<head>
<title>Interactive App</title>
@alpine.Scripts()
</head>
<body>
<div x-data="{ count: 0 }">
<button @click="count++">Increment</button>
<span x-text="count"></span>
</div>
</body>
</html>
}- ✅ Box - Polymorphic container with responsive props
- ✅ Flex - Flexbox layout with direction and alignment
- ✅ Grid - CSS Grid layout with responsive columns
- ✅ Stack - VStack/HStack for vertical/horizontal layouts
- ✅ Center - Centered container with responsive centering
- ✅ Container - Responsive container with max-width
- ✅ Text - Typography primitive with semantic HTML
- ✅ Spacer - Flexible spacer for layouts
- ✅ Button - All variants (Primary, Secondary, Destructive, Outline, Ghost, Link)
- ✅ Button Group - Grouped buttons with gap control
- ✅ Icon Button - Compact icon-only buttons
- ✅ Card - Compound component (Header, Title, Description, Content, Footer)
- ✅ Badge - Status indicators and labels
- ✅ Avatar - User avatars with image and fallback
- ✅ Alert - Alert messages with variants (Info, Success, Warning, Error)
- ✅ Separator - Horizontal/vertical dividers
- ✅ Empty State - Empty state placeholders
- ✅ List - List containers with list items
- ✅ Navbar - Navigation bar component
- ✅ Breadcrumb - Breadcrumb navigation
- ✅ Tabs - Tabbed navigation and content
- ✅ Menu - Menu and menu items
- ✅ Sidebar - Collapsible sidebar navigation
- ✅ Pagination - Page navigation controls
- ✅ Form - Form wrapper with validation helpers
- ✅ Label - Accessible form labels
- ✅ Input - Text inputs with variants and validation states
- ✅ Input Group - Input with icons and addons
- ✅ Textarea - Multi-line text input
- ✅ Checkbox - Checkbox inputs with labels
- ✅ Radio - Radio buttons with radio groups
- ✅ Switch - Toggle switches
- ✅ Select - Native select dropdowns
- ✅ Slider - Range sliders
- ✅ Modal - Modal dialogs
- ✅ Dialog - Dialog component
- ✅ Alert Dialog - Confirmation dialogs
- ✅ Drawer - Slide-out panels
- ✅ Sheet - Bottom/side sheets
- ✅ Dropdown - Dropdown menus
- ✅ Context Menu - Right-click context menus
- ✅ Popover - Floating popovers
- ✅ Tooltip - Hover tooltips
- ✅ Toast - Toast notifications with toaster
- ✅ Spinner - Loading spinners
- ✅ Skeleton - Loading placeholders
- ✅ Progress - Progress bars
- ✅ Table - Data tables with header, body, rows, and cells
- ✅ DataTable - Advanced tables with sorting, filtering, and pagination
import "github.com/xraph/forgeui/components/button"
// Primary button
@button.Button(button.Props{Variant: button.VariantDefault}) {
Save
}
// Destructive button
@button.Button(button.Props{Variant: button.VariantDestructive, Size: button.SizeLg}) {
Delete
}import "github.com/xraph/forgeui/components/card"
@card.Card(card.Props{}) {
@card.Header() {
@card.Title() { Settings }
@card.Description() { Manage your account settings }
}
@card.Content() {
// Your content here
}
@card.Footer() {
@button.Button(button.Props{}) { Save Changes }
}
}import "github.com/xraph/forgeui/primitives"
@primitives.Container(primitives.ContainerProps{}) {
@primitives.Stack(primitives.StackProps{Direction: "vertical", Gap: "8"}) {
@primitives.Text(primitives.TextProps{As: "h1", Size: "text-4xl", Weight: "font-bold"}) {
Dashboard
}
@primitives.Grid(primitives.GridProps{Cols: 1, ColsMD: 2, ColsLG: 3, Gap: "6"}) {
// Grid items here
}
}
}Production-ready HTTP routing with pattern matching and middleware:
app := forgeui.New()
// Static routes
app.Get("/", HomePage)
app.Get("/about", AboutPage)
// Path parameters
app.Get("/users/:id", UserProfile)
app.Get("/users/:userId/posts/:postId", PostDetail)
// Wildcards
app.Get("/files/*filepath", ServeFile)
// Middleware
app.Use(router.Logger())
app.Use(router.Recovery())
app.Use(router.CORS("*"))
// Route-specific middleware
route := app.Get("/admin", AdminDashboard)
route.WithMiddleware(AuthMiddleware)
// Named routes for URL generation
app.Router().Name("user.post", route)
url := app.Router().URL("user.post", userID, postID)Access request data with rich context utilities:
func UserProfile(ctx *router.PageContext) (templ.Component, error) {
// Path parameters
id := ctx.Param("id")
userID, _ := ctx.ParamInt("id")
// Query parameters
query := ctx.Query("q")
page, _ := ctx.QueryInt("page")
// Headers and cookies
auth := ctx.Header("Authorization")
cookie, _ := ctx.Cookie("session")
// Context values (set by middleware)
uid := ctx.GetInt("user_id")
return UserProfileView(id), nil
}See router/README.md for complete documentation.
Call Go functions directly from JavaScript using JSON-RPC 2.0:
b := bridge.New()
// Register Go functions
b.Register("createUser", func(ctx bridge.Context, input struct {
Name string `json:"name"`
Email string `json:"email"`
}) (struct {
ID int `json:"id"`
Name string `json:"name"`
}, error) {
user := createUserInDB(input.Name, input.Email)
return struct {
ID int `json:"id"`
Name string `json:"name"`
}{ID: user.ID, Name: user.Name}, nil
})
// Function options
b.Register("adminAction", handler,
bridge.RequireAuth(),
bridge.RequireRoles("admin"),
bridge.WithRateLimit(10),
bridge.WithTimeout(10*time.Second),
)
// Enable bridge on router
bridge.EnableBridge(app.Router(), b)// Include bridge scripts in your layout
@bridge.BridgeScripts(bridge.ScriptConfig{
Endpoint: "/api/bridge",
CSRFToken: csrfToken,
IncludeAlpine: true,
})
// Alpine.js integration
<button @click="result = await $bridge.call('createUser', {name, email})">
Create User
</button>Features:
- HTTP (JSON-RPC 2.0), WebSocket, and SSE transports
- Built-in authentication, authorization, and rate limiting
- Automatic parameter validation
- CSRF protection
- Caching support
- Alpine.js magic helpers
See bridge/README.md for complete documentation.
Complete HTMX support with type-safe attribute helpers:
// In your layout templ file
@htmx.Scripts()
// HTMX attributes on elements
<button { htmx.HxGet("/api/users")... } { htmx.HxTarget("#user-list")... } { htmx.HxSwap("innerHTML")... }>
Load Users
</button>
// Advanced triggers
<input { htmx.HxTriggerDebounce("keyup", "500ms")... } { htmx.HxGet("/search")... }/>Server-side detection and response headers work the same:
func handler(w http.ResponseWriter, r *http.Request) {
if htmx.IsHTMX(r) {
renderPartial(w)
} else {
renderFullPage(w)
}
}
htmx.TriggerEvent(w, "refresh")
htmx.SetHTMXRedirect(w, "/login")See htmx/README.md for complete documentation.
Seamless Alpine.js integration with directives, stores, and plugins:
// Include Alpine.js in your layout
@alpine.Scripts()
// Alpine directives on elements
<div x-data="{ count: 0 }">
<button @click="count++">Increment</button>
<span x-text="count"></span>
</div>
// Or use the helper functions for programmatic attributes
<div { alpine.XShow("isVisible")... } { alpine.XTransitionSimple()... }>
Content
</div>Alpine stores and custom directives in Go:
alpine.Store("app", map[string]any{
"user": nil,
"isLoggedIn": false,
})
alpine.Directive("click-outside", `(el, {expression}, {evaluate}) => {
// directive implementation
}`)1600+ Lucide icons with full customization:
// Basic usage in templ files
@icons.Check()
@icons.Search()
@icons.User()
// Customization
@icons.Check(icons.WithSize(24), icons.WithColor("green"), icons.WithClass("text-green-500"))
// In buttons
@button.Button(button.Props{}) {
@icons.Plus(icons.WithSize(16))
Add Item
}
// Loading spinner
@icons.Loader(icons.WithSize(20), icons.WithClass("animate-spin"))See icons/README.md for complete documentation.
Extensible plugin architecture with dependency management:
// Create a plugin
type MyPlugin struct {
*plugin.PluginBase
}
func New() *MyPlugin {
return &MyPlugin{
PluginBase: plugin.NewPluginBase(plugin.PluginInfo{
Name: "my-plugin",
Version: "1.0.0",
Dependencies: []plugin.Dependency{
{Name: "other-plugin", Version: ">=1.0.0"},
},
}),
}
}
func (p *MyPlugin) Init(ctx context.Context, r *plugin.Registry) error {
// Initialize plugin
return nil
}
// Use plugins
registry := plugin.NewRegistry()
registry.Use(
myplugin.New(),
otherplugin.New(),
)
registry.Initialize(ctx)
defer registry.Shutdown(ctx)Plugin Types:
- Component plugins (extend UI components)
- Alpine plugins (scripts, directives, stores)
- Theme plugins (custom themes and fonts)
- Middleware plugins (HTTP middleware)
See plugin/README.md for complete documentation.
Built-in asset management with Tailwind CSS, esbuild, and fingerprinting:
app := forgeui.New()
// Configure assets
app.WithAssets(assets.Config{
Enabled: true,
OutputDir: "./dist",
Minify: true,
Fingerprint: true,
Tailwind: assets.TailwindConfig{
Input: "./styles/input.css",
Output: "./dist/styles.css",
ConfigFile: "./tailwind.config.js",
},
ESBuild: assets.ESBuildConfig{
EntryPoints: []string{"./js/app.js"},
Outdir: "./dist/js",
},
})
// Development server with hot-reload
if err := app.StartDevServer(":3000"); err != nil {
log.Fatal(err)
}Features:
- Tailwind CSS compilation
- JavaScript bundling with esbuild
- File fingerprinting for cache busting
- Hot-reload development server
- Asset manifest generation
See assets/README.md for complete documentation.
Customizable themes with CSS variables:
// Use built-in theme
app := forgeui.New(
forgeui.WithThemeName("default"),
)
// Create custom theme
customTheme := theme.Theme{
Colors: theme.ColorTokens{
Primary: "#3b82f6",
Secondary: "#64748b",
Background: "#ffffff",
Foreground: "#0f172a",
},
Radius: theme.RadiusTokens{
Default: "0.5rem",
Button: "0.375rem",
Card: "0.75rem",
},
}
app.RegisterTheme("custom", customTheme)Command-line tools for project management:
# Create new project
forgeui new myproject
# Create new component
forgeui create component MyComponent
# Create new page
forgeui create page HomePage
# Run development server
forgeui dev
# Build for production
forgeui buildForgeUI follows a layered architecture designed for scalability and maintainability:
┌─────────────────────────────────────┐
│ Application Layer │
│ (Your App, Examples, CLI) │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ Integration Layer │
│ (Router, Bridge, HTMX, Alpine) │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ Components Layer │
│ (UI Components, Icons, Layouts) │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ Foundation Layer │
│ (Primitives, CVA, Theme, Assets) │
└─────────────────────────────────────┘
- Composability: All components are composable templ components
- Type Safety: Full Go type checking at compile time
- Minimal Dependencies: Core components have zero client-side dependencies
- Progressive Enhancement: Add interactivity with Alpine.js and HTMX
- Unidirectional Flow: Higher layers depend on lower layers, never the reverse
ForgeUI includes comprehensive test coverage across all packages:
# Run all tests
go test ./...
# Run with coverage
go test -cover ./...
# Run with race detection
go test -race ./...
# Run specific package tests
go test ./components/button/...
go test ./router/...
# Generate coverage report
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.outComponents and features include:
- Unit tests: Testing individual functions and components
- Integration tests: Testing component interactions
- HTTP tests: Using
httptestfor router and bridge testing - Golden files: Snapshot testing for component output
app := forgeui.New(
// Core options
forgeui.WithDebug(true),
forgeui.WithThemeName("default"),
forgeui.WithStaticPath("/static"),
forgeui.WithDefaultSize(forgeui.SizeMD),
forgeui.WithDefaultVariant(forgeui.VariantDefault),
forgeui.WithDefaultRadius(forgeui.RadiusMD),
// Assets configuration
forgeui.WithAssets(assets.Config{
Enabled: true,
OutputDir: "./dist",
Minify: true,
Fingerprint: true,
}),
)
// Initialize the application
if err := app.Initialize(context.Background()); err != nil {
log.Fatal(err)
}
// Start HTTP server
http.ListenAndServe(":8080", app.Router())var cfg forgeui.Config
if os.Getenv("ENV") == "production" {
cfg = forgeui.Config{
Debug: false,
StaticPath: "/static",
Assets: assets.Config{
Enabled: true,
Minify: true,
Fingerprint: true,
},
}
} else {
cfg = forgeui.Config{
Debug: true,
StaticPath: "/static",
Assets: assets.Config{
Enabled: true,
Minify: false,
Fingerprint: false,
},
}
}
app := forgeui.NewWithConfig(cfg)The example/ directory contains complete working examples:
cd example
go run main.goVisit http://localhost:8080 to see:
- Component Showcase: All UI components with variations
- Dashboard Demo: Real-world dashboard layout
- Interactive Examples: Alpine.js and HTMX integration
- Router Demo: Client-side routing with Pinecone Router
- Bridge Demo: Go-JavaScript RPC examples
- Assets Demo: Asset pipeline in action
Each package includes comprehensive documentation:
- Router - HTTP routing system
- Bridge - Go-JavaScript RPC bridge
- HTMX - HTMX integration
- Icons - Icon system
- Plugin - Plugin architecture
- Assets - Asset management
- Components - Individual component docs
forgeui/
├── alpine/ # Alpine.js integration
├── animation/ # Animation and transition utilities
├── assets/ # Asset pipeline (CSS, JS, Tailwind)
├── bridge/ # Go-JavaScript RPC bridge
├── cli/ # Command-line tools
├── components/ # UI components
│ ├── button/
│ ├── card/
│ ├── form/
│ └── ...
├── example/ # Example applications
├── htmx/ # HTMX integration
├── icons/ # Icon system (Lucide)
├── htmx/ # HTMX integration
├── plugin/ # Plugin system
├── primitives/ # Layout primitives
├── router/ # HTTP router
├── theme/ # Theme system
└── ...
ForgeUI welcomes contributions! Follow these guidelines:
- Follow Go conventions: Use
gofmt,golangci-lint - Use templ templates: Write UI in
.templfiles with Props structs - Use templui components: Leverage templui as the base component library
- Documentation: Document all exported functions with examples
- Type safety: Leverage Go's type system
- Respect architecture layers: Components should only import from lower layers
- Test thoroughly: Aim for 80%+ coverage
- Include examples: Add examples to component documentation
- Accessibility: Follow ARIA guidelines
- Mobile-first: Ensure responsive design
# Run tests
go test ./...
# Run with coverage
go test -cover ./...
# Run linter
golangci-lint run- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Write tests for your changes
- Ensure all tests pass
- Update documentation
- Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
// ✅ Good: Compose templ components
@button.Button(button.Props{}) {
@icons.Plus(icons.WithSize(16))
Add Item
}// ✅ Good: Return errors from handlers
func UserProfile(ctx *router.PageContext) (templ.Component, error) {
user, err := getUser(ctx.Param("id"))
if err != nil {
return nil, err
}
return UserProfileView(user), nil
}
// ❌ Bad: Don't panic or ignore errors// ✅ Good: Pass context through the stack
func handler(ctx *router.PageContext) (templ.Component, error) {
user := ctx.GetString("user_id")
return UserView(user), nil
}
// ❌ Bad: Don't use global variablesForgeUI is designed for performance:
- Fast: Pure Go rendering with minimal overhead
- Efficient: No JavaScript runtime required for basic pages
- Scalable: Handles thousands of requests per second
- Optimized: Built-in minification and fingerprinting
- Cached: Long-lived browser caching with cache busting
- Small: Tailwind CSS purging removes unused styles
- Lightweight: Start with 0KB of JavaScript
- Optional: Add Alpine.js (15KB) or HTMX (14KB) only when needed
- Lazy: Load components on demand
Typical performance on modest hardware (4 core, 8GB RAM):
- Simple page render: ~0.5ms
- Complex dashboard: ~2ms
- Component with children: ~0.1ms per child
- Throughput: 10,000+ req/s
Before deploying to production:
- Set
WithDebug(false) - Enable asset minification
- Enable asset fingerprinting
- Use HTTPS (TLS)
- Set up proper logging
- Configure CORS if needed
- Set up rate limiting
- Enable CSRF protection
- Configure proper caching headers
- Test with production data
- Set up monitoring and alerts
Components not rendering?
- Check if you've initialized the app with
app.Initialize(ctx) - Verify Tailwind CSS is included in your HTML
Styles not applying?
- Ensure Tailwind CSS is properly configured
- Check if the asset pipeline is enabled
- Verify the CSS file is being served
HTMX not working?
- Include
htmx.Scripts()in your HTML head - Check browser console for errors
- Verify HTMX attributes are correct
Alpine.js not working?
- Include
alpine.Scripts()in your HTML head - Check for JavaScript errors in console
- Verify Alpine syntax is correct
- GitHub Issues: Report bugs and request features
- Discussions: Ask questions and share ideas
- Examples: Check the
example/directory for working code
Planned features and improvements:
- More component variants and customization options
- Server-side validation helpers
- Form builder with automatic validation
- More built-in plugins
- WebSocket utilities
- Admin panel template
- CLI improvements (scaffolding, generators)
- Performance monitoring utilities
- i18n support
MIT License - See LICENSE file for details
ForgeUI stands on the shoulders of giants:
- templ - Type-safe HTML templating for Go
- templui - shadcn-inspired component library for templ
- shadcn/ui - Design inspiration and component patterns
- Tailwind CSS - Utility-first CSS framework
- Alpine.js - Lightweight JavaScript framework
- HTMX - High power tools for HTML
- Lucide - Beautiful icon library
Made with ❤️ for the Go community