Goshtoso

August 25, 2026 · View on GitHub

Goshtoso mascot

CI Codecov coverage Go Reference Go Report Card Latest release License: MIT

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:

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.go is generated by templ generate
  • assets/styles.css is generated by just 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.