A Go/templ port of shadcn/ui components that maintains pixel-perfect visual and behavioral parity with minimal JavaScript (lightweight 15KB Datastar library for reactivity).
See datastar-ui.com for component demos.
- 🚀 Server-side rendered components with Go/templ
- ⚡ Reactive UI powered by Datastar signals
- 🎨 Identical styling to shadcn/ui using Tailwind CSS
- 📦 Lightweight - only 15KB Datastar runtime
- 🔧 Type-safe component args with Go structs
- 🌙 Dark mode support built-in
- ♿ Accessible with proper ARIA attributes
- Go 1.24+
- Just - command runner
- Air - live reload for Go
- templ - Go templating engine
- tailwindcss standalone CLI
# start the Tailwind CSS watcher:
just tailwind
# start the Go server with live reload:
just watch
see demo site at http://localhost:4242
The development environment will automatically:
- ✅ Rebuild Go templates when
.templ
files change - ✅ Recompile CSS when Tailwind classes are added/removed
- ✅ Restart the server when Go code changes
datastarui/
├── components/ # Reusable UI components
│ ├── button/ # Button component
│ │ ├── button.templ # Template file
│ │ ├── args.go # Component arguments
│ │ └── variants.go # CSS class variants
│ └── select/ # Select component (fully refactored)
├── utils/ # Utility libraries
│ ├── signals.go # Signal management with namespacing
│ ├── expressions.go # Datastar expression builders
│ └── data_class.go # Conditional CSS class helpers
├── docs/ # Documentation
│ ├── guide.md # Development patterns guide
│ ├── debugging.md # Testing and troubleshooting
│ ├── playwright.md # Browser automation testing
│ ├── signals.md # Signal management reference
│ └── templ.md # templ syntax guide
├── pages/ # Page templates
│ └── components/ # Component demo pages
├── layouts/ # Layout templates
├── static/ # Static assets
│ └── css/ # Tailwind CSS files
└── main.go # Server entry point
Each component follows a consistent 3-file pattern with utility-driven Datastar integration:
package button
import "github.com/coreycole/datastarui/utils"
type ButtonSignals struct {
Clicked bool `json:"clicked"`
Loading bool `json:"loading"`
}
templ Button(args ButtonProps) {
{{
// Use utilities for signal management
signals := utils.Signals(args.ID, ButtonSignals{
Clicked: false,
Loading: args.Loading,
})
// Use expression builders for click handlers
clickHandler := utils.NewExpression().
Statement("evt.preventDefault()").
SetSignal("clicked", "true").
Build()
}}
<button
type={ args.Type }
class={ buttonVariants(args.Variant, args.Size, args.Class) }
disabled?={ args.Disabled }
data-signals={ signals.DataSignals }
data-on-click={ clickHandler }
{ args.Attributes... }
>
{ children... }
</button>
}
package button
import "github.com/a-h/templ"
type ButtonProps struct {
ID string // Component identifier for signals
Variant string // "default", "destructive", "outline"
Size string // "default", "sm", "lg", "icon"
Class string // Additional CSS classes
Attributes templ.Attributes // HTML attributes
Disabled bool // Interactive state
Loading bool // Loading state
Type string // Button type
}
package button
import "github.com/coreycole/datastarui/utils"
func buttonVariants(variant, size, className string) string {
// Exact CSS classes from shadcn/ui
baseClasses := "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
variantClasses := map[string]string{
"default": "bg-primary text-primary-foreground hover:bg-primary/90",
"destructive": "bg-destructive text-destructive-foreground hover:bg-destructive/90",
"outline": "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
"secondary": "bg-secondary text-secondary-foreground hover:bg-secondary/80",
"ghost": "hover:bg-accent hover:text-accent-foreground",
"link": "text-primary underline-offset-4 hover:underline",
}
sizeClasses := map[string]string{
"default": "h-10 px-4 py-2",
"sm": "h-9 rounded-md px-3",
"lg": "h-11 rounded-md px-8",
"icon": "h-10 w-10",
}
return utils.TwMerge(baseClasses, variantClasses[variant], sizeClasses[size], className)
}
The project uses the same design tokens as shadcn/ui:
- Colors: CSS custom properties for theming
- Typography: Tailwind's font system
- Spacing: Consistent spacing scale
- Shadows: Subtle elevation system
- Borders: Rounded corners and borders
- Pick a component from the shadcn/ui registry
- Follow the utility-driven architecture using expression builders
- Create comprehensive demos showing all variants
- Playwright Testing - Browser automation testing
- Datastar Documentation - Reactivity framework
- templ Documentation - Go templating engine
- shadcn/ui - Original component library
MIT License - see LICENSE for details.