Goshtoso
August 25, 2026 · View on GitHub
Goshtoso is a Go UI component library for server-rendered web apps. Add pre-generated templ components, serve the bundled assets, and use HTMX or Alpine.js only where the interface needs interaction.
The project began as a hard fork of PenguinUI. It now provides a Go-first component system for applications that own versioned dependencies and render most HTML on the server.
Goshtoso is actively evolving. The components are usable, but the API surface is still being refined as the library moves toward a stable public release. See ROADMAP.md for the alpha stability policy and release path.
Highlights
- 56 public component packages, 52 documentation pages, and 85 renderable primitives for composition, forms, navigation, overlays, data display, feedback, layout, and richer inputs.
- Server-rendered by default with HTMX-friendly markup and Alpine.js where instant local interaction makes sense.
- Bundled assets for Tailwind CSS, Alpine.js, HTMX, htmx extensions, fonts, and images. No runtime CDN dependency is required.
- Theme system included with light/dark support and 16 built-in themes.
- Two-module repository: a slim publishable library at the repo root and a
demo/test site under
site/. - Go-native examples and tests using templ generation and Playwright-backed E2E coverage.
Quick Start
Goshtoso requires Go 1.27.0 or newer.
Install the library:
go get github.com/araihu/goshtoso@latest
Mount the embedded assets in your server:
package main
import (
"net/http"
"github.com/araihu/goshtoso/assets"
)
func main() {
http.Handle("/assets/", assets.Handler())
http.ListenAndServe(":8080", nil)
}
Include Goshtoso's CSS and JavaScript in your page shell:
import "github.com/araihu/goshtoso/components/head"
templ Layout() {
<html>
<head>
@head.Dependencies()
</head>
<body>
{ children... }
</body>
</html>
}
head.Dependencies() uses version-pinned unpkg URLs first and automatically
retries the matching embedded JavaScript when a CDN download fails. The CSS,
loader, first-party helpers, and fallback files still come from
assets.Handler(); third-party bytes are protected by generated SHA-384 SRI.
Consumers that need content-addressed cache keys can use
assets.RuntimeHash(role) or inspect assets.MuambaResources() without
copying generated paths or hashes.
For an offline PWA or desktop/mobile WebView, an air-gapped
deployment, or another application that must never request a CDN, use:
@head.Dependencies(head.WithLocalRuntime())
Functional options can replace the CDN and local URL of each dependency, disable fallback, omit an application-owned runtime, or move the stylesheet, loader, and combobox helper. See docs/USAGE.md.
Render components from their packages:
import "github.com/araihu/goshtoso/components/button"
templ Example() {
@button.Button(
button.WithTone(button.TonePrimary),
button.WithType("button"),
) {
Save changes
}
}
Goshtoso components ship pre-generated, so consumers do not run
templ generate on the library itself. You still run templ generate for your
own .templ files.
For a task-by-task integration guide, including your first component, custom
Tailwind builds, and manual asset wiring, see docs/USAGE.md. The
Goshtoso Component Model documents the common
component interface, concrete return values, constructor styles, stable Kind
identity, and rendered defaults.
Release changes are recorded in the changelog; applications
upgrading from v0.0.11 should follow the
component API migration guide.
Maintainers updating repository-owned brand, theme, or UI-icon fallbacks should
follow the immutable Arai Hu asset update contract.
AI Agent Skill
Goshtoso ships an installable skill for AI coding agents that need to use the
library inside consumer applications. It teaches agents how to install the Go
module, serve bundled assets, wire head.Dependencies(), import components,
choose a CSS strategy, write a low-interaction surface brief, route the real
task into supported application patterns, reject generic design reflexes, and
verify the result in the browser. The composition contracts remain App Shell,
Operations List, Detail Workspace, and Multi-step Workflow.
Install the skill into a project or agent workspace:
npx skills add araihu/goshtoso --skill using-goshtoso
For Codex:
npx skills add araihu/goshtoso --skill using-goshtoso --agent codex
Use it without installing files:
npx skills use araihu/goshtoso --skill using-goshtoso
The skill is intentionally consumer-focused. It does not cover maintaining
Goshtoso itself, editing component internals, or running releases. The public
docs site includes an AI Agents page at /docs/agents. The installed skill also
ships a design-intelligence reference,
an application patterns reference,
and a visual acceptance checklist.
For a public organization, product, or publication site, start with the
copyable examples/brand-site fixture rather than an
application shell. It generates static HTML and makes the product-owned
typography, art direction, and content hierarchy explicit. Create a fresh copy
with go run github.com/araihu/goshtoso/cmd/goshtoso@latest -init-brand-site=./my-site.
Component Catalog
All components are imported from:
github.com/araihu/goshtoso/components/<name>
Current components:
accordion actiongroup alert appshell avatar badge
banner breadcrumbs button card carousel chatbubble
checkbox codeblock combobox drawer dropdown emptystate
fileinput form head kbd link modal
navbar pageheader pagination palette panel radio
range rating schemaform search select sidebar
skeleton spinner steps structuredinput table tabs
tagslist textarea textinput toast toolbar toggle
tooltip
Run the demo site to explore component options, API tables, HTMX behavior, Alpine.js states, themes, and example apps:
go run ./site/cmd/server
Then open:
- http://localhost:8090/getting-started
- http://localhost:8090/components/accordion
- http://localhost:8090/examples/todo
- http://localhost:8090/examples/logs
The public documentation site is available at https://goshtoso.araihu.com/.
Using Assets
The recommended path is to serve Goshtoso's embedded assets:
mux := http.NewServeMux()
mux.Handle("GET /assets/", assets.Handler())
and let @head.Dependencies() emit the matching stylesheet and script tags.
The default loader tries version-pinned CDN URLs for Alpine.js and HTMX, then
falls back to the same versions under /assets/js/runtime/. Use
head.WithLocalRuntime() when an offline application such as a PWA or native
WebView must be fully local.
assets.RuntimeHash(role) exposes normalized SHA-384 hashes for vendored
runtime roles. assets.MuambaHash(resource, download) and
assets.MuambaResources() expose the complete embedded acquisition inventory.
If you maintain a custom Tailwind build, Goshtoso also ships a CLI that extracts the compiled CSS or theme source:
go run github.com/araihu/goshtoso/cmd/goshtoso@latest -out=css/goshtoso-base.css
See docs/USAGE.md for the full asset strategy. Release maintainers should also use docs/RELEASE_CHECKLIST.md before tagging.
Sprite Icons
components/icon renders accessible SVG <use> references. The bundled
components/icon/heroicons package provides typed symbols and a same-origin
default sprite URL:
import (
"github.com/araihu/goshtoso/components/icon"
"github.com/araihu/goshtoso/components/icon/heroicons"
)
templ SaveIcon() {
@icon.Icon(icon.Config{
SpriteURL: heroicons.SpriteURL,
Symbol: heroicons.Icon16SolidCheck,
Label: "Saved",
})
}
Use a relative, same-origin sprite URL by default. ModeInline resolves an
already-present symbol from the current document; cross-origin external sprites
depend on browser support and CORS, and HTTPS pages should not reference an HTTP
sprite. A blank label and Decorative: true both produce a decorative icon.
See docs/USAGE.md for generator and deployment
details.
Repository Layout
goshtoso/
├── cmd/ # Thin command entry points
├── components/ # Publishable component library
├── assets/ # Embedded CSS, JS, fonts, and images
├── css/ # Tailwind source
├── docs/ # Consumer and project documentation
├── examples/ # Standalone examples
├── internal/ # Generator internals used by cmd/* tools
└── site/ # Demo site, example app pages, server, E2E tests
The root module is github.com/araihu/goshtoso. The site/ directory is a
separate module for the demo website and test harness.
For local development, create a Go workspace once per clone so the site imports your working-tree copy of the library:
go work init . ./site
Development
Dagger CI locally
All repository CI gates are implemented by the Dagger module pinned to
v0.21.8; GitHub Actions only supplies event routing, immutable identities,
secrets, and artifact/publication adapters. Run the same safe gates locally:
nonce=$(uuidgen)
dagger call lint-build --source=. --cache-partition=local
dagger call required --source=. --cache-partition=local
dagger call docs --source=. --cache-partition=local
# Supply a committed range for conservative focused E2E selection. Dirty
# staged, unstaged, or untracked source forces the full suite so selection and
# the Dagger source snapshot cannot diverge.
base=$(git merge-base origin/main HEAD)
scripts/materialize-e2e-changes "$base" HEAD .e2e-changes
dagger call tests --source=. --changes=.e2e-changes \
--cache-partition=local --run-nonce="$nonce" export --path=.dagger-output
Release verification is also safe locally and performs no publication:
dagger call release-verify --source=. --cache-partition=local \
--run-nonce="$(uuidgen)" export --path=.coverage
Cache namespaces are explicitly partitioned into local, trusted CI, and
untrusted CI domains. Every effectful or externally mutable entry point also
requires a fresh nonce; GitHub uses run_id-run_attempt.
Useful commands from the repo root:
# Generate *_templ.go files after editing .templ sources
just generate
# Rebuild the embedded Tailwind CSS after editing CSS/theme sources
just css
# Run the demo server on :8090
just dev
# Build the demo server
just build
Run tests:
# Root and site unit tests
just test
# Full Playwright E2E suite
just test-e2e
# Release-equivalent unit + Playwright coverage
just coverage
Release coverage keeps two reports. When CODECOV_TOKEN is configured, the
public Codecov report measures
authored Go source and excludes only generated *_templ.go files. Release
artifacts always retain the full generated-inclusive profile and HTML report.
Both reports come from the same root, site, and real-browser test run.
Run lint checks per module:
golangci-lint run
cd site && golangci-lint run
Generated files are part of the repo, but should not be edited by hand:
*_templ.gois generated bytempl generateassets/styles.cssis generated byjust css
Contributing
See CONTRIBUTING.md for contribution guidelines and CODE_OF_CONDUCT.md for community expectations.
When adding or changing components, keep the component source, demo page, E2E coverage, generated templ output, CSS output, and usage reference in sync.
Credits
Goshtoso began as a hard fork of PenguinUI by Salar Houshvand, transformed from static HTML/Alpine.js examples into an importable Go component library.
License
MIT. See LICENSE.