GOTH stack

Stop rewriting the same components.

kraft-ui is a typed component library for Go, Templ, HTMX, and Tailwind CSS. Every component is a Go struct with typed props, consistent design, and zero JavaScript dependencies.

An input field with a label and an error.

Something you write on every form page. Here is the difference.

Raw Tailwind in Templ
16 lines
html
<div class="flex flex-col gap-1.5">
  <label class="text-sm font-medium text-text-primary">
    Email
  </label>
  <input
    type="email"
    placeholder="you@example.com"
    class="rounded-md border border-error-500
           px-3 py-2 text-sm bg-surface
           text-text-primary
           placeholder:text-text-muted
           focus:outline-none focus:ring-2
           focus:ring-error-500
           focus:border-error-500
           transition-colors"
  />
  <p class="text-xs text-error-600">
    Invalid email address
  </p>
</div>

<!-- Repeat this. On every form field.
     Every dev on your team does it
     differently. -->
With kraft-ui
5 lines
go
@input.Input(input.Props{
  Type:  "email",
  Label: "Email",
  Error: "Invalid email address",
})

// Same markup. Same styles.
// Consistent across every field.
// IDE guides you through every prop.
// One place to update when design changes.

11 fewer lines. But that is not the real win.

The real win is that every developer on your team writes it the same way. No one argues about class order. No one forgets the error state. No one uses a different focus ring on a different page. When the design changes, you update one file.

1

source of truth

0

class debates

A button that triggers an HTMX request.

Raw Tailwind means memorising 10+ utility classes for every button state. kraft-ui handles the styles. You handle the logic.

Raw Tailwind in Templ 15 lines
html
<button
  type="button"
  class="inline-flex items-center justify-center
         gap-2 rounded-md px-4 py-2
         text-sm font-medium
         bg-brand-500 text-white
         hover:bg-brand-600 active:bg-brand-700
         focus:outline-none focus:ring-2
         focus:ring-brand-500 focus:ring-offset-2
         disabled:opacity-50
         disabled:cursor-not-allowed
         transition-colors"
  hx-post="/api/save"
  hx-target="#result"
>
  Save changes
</button>
With kraft-ui 7 lines
go
@button.Button(button.Props{
  Variant: button.VariantPrimary,
  Attrs: templ.Attributes{
    "hx-post":   "/api/save",
    "hx-target": "#result",
  },
}) { Save changes }

// Every hx-* attribute works.
// Disabled state, loading state,
// sizes, variants — all typed.

Pass any hx-*, data-*, or x-* attribute via templ.Attributes. The components are built for the full GOTH stack from day one.

Typed props, always

Every component takes a Go struct. Your IDE autocompletes variants, sizes, and states. No class strings to memorise or typo.

HTMX-first design

Pass any hx-* attribute via templ.Attributes. Components are built for server-driven interactions from the start.

Own your code

Use as a Go module or copy components directly into your project. No black box. MIT licensed. Readable source.

See what you get

Buttons

Badges and Alerts

Default Secondary Success Warning Destructive Info Outline Live

Card and Inputs

Typed components

Consistent design across your whole app.

Update one component, every instance in the app reflects the change.

We never share your email.

Too short