🕍

TemplでGoのHTMLレンダリングを快適に!型安全なコンポーネント指向テンプレートエンジンの魅力

に公開

「GoでWebアプリを作るとき、HTMLのレンダリングってどうしてますか?」

標準パッケージの html/template は非常に強力で広く使われていますが、「型安全じゃない」「コンポーネントの再利用がしにくい」「エディタの補完が効かない」といった点で、少しモヤモヤすることはありませんか?特にReactやVueなどのモダンなフロントエンドフレームワークに慣れていると、そのギャップを強く感じるかもしれません。

そんな悩みを一気に解決してくれるのが、今回紹介する Templ です!

Templは、GoのためのHTMLテンプレート言語であり、JSXライクな構文でGoのコードとHTMLをシームレスに記述できる画期的なツールです。GitHubリポジトリでは 10,000以上のスターを獲得しており(2026年3月時点)、Go界隈でじわじわと注目度が上がっています。この記事では、Templの魅力から基本的な使い方、そして開発を快適にするコマンドや設定項目までをたっぷり解説します。


Templとは?

Templは、Go言語でHTMLユーザーインターフェースを構築するためのテンプレート言語です。.templ という拡張子のファイルにHTMLとGoのコードを混在させて書き、それを専用のCLIツールで純粋なGoのコードにコンパイルします。

公式サイトでは以下のように説明されています。

Create components that render fragments of HTML and compose them to create screens, pages, documents, or apps.
(HTMLの断片をレンダリングするコンポーネントを作成し、それらを組み合わせて画面、ページ、ドキュメント、またはアプリを作成します。)

最もシンプルなTemplコンポーネントはこんな感じです。

package main

templ Hello(name string) {
  <div>Hello, { name }</div>
}

templ Greeting(person Person) {
  <div class="greeting">
    @Hello(person.Name)
  </div>
}

@ を使って別のコンポーネントを呼び出せるのが特徴的ですね。

Templの主な特徴

Templが多くのGo開発者から注目を集めているのには、いくつかの明確な理由があります。公式サイトでは以下の特徴が挙げられています。

特徴 説明
Server-side rendering サーバーレス関数、Dockerコンテナ、通常のGoプログラムとしてデプロイ可能
Static rendering 静的HTMLファイルを生成して自由にデプロイ可能
Compiled code コンポーネントは高パフォーマンスなGoコードにコンパイルされる
Use Go 任意のGoコードを呼び出せ、ifswitchfor文をそのまま使える
No JavaScript クライアント・サーバーサイドのJavaScriptが不要
Great developer experience IDEのオートコンプリートに対応

特に「型安全」という点が大きな強みです。テンプレートがGoのコードにコンパイルされるため、変数名の間違いや型の不一致はコンパイルエラーとして事前に検知されます。実行時にテンプレートのパースエラーで落ちる心配がありません。

また、最近流行りの htmx との相性も抜群で、Go + Templ + htmx のスタックは非常に強力な選択肢として注目されています。


クイックスタート:実際に動かしてみよう

百聞は一見に如かず。実際にTemplを使って簡単なWebサーバーを立ち上げてみましょう。

1. インストール

まずはプロジェクトをセットアップし、TemplのCLIツールをインストールします。

mkdir templ-hello
cd templ-hello
go mod init example.com/templ-hello
go get github.com/a-h/templ

グローバルインストール(Go 1.24以降推奨)

go install github.com/a-h/templ/cmd/templ@latest

これで templ コマンドがPATHに追加されます。

プロジェクトローカルインストール(Go 1.24の tool ディレクティブを使用)

go get -tool github.com/a-h/templ/cmd/templ@latest

この場合は templ の代わりに go tool templ を使います。

2. コンポーネントの作成

hello.templ というファイルを作成し、以下のコードを記述します。

package main

templ hello(name string) {
  <div>Hello, { name }!</div>
}

非常にシンプルですね。templ キーワードを使ってコンポーネントを定義し、引数として name string を受け取っています。HTMLの中では { } で囲むことでGoの変数を展開できます。

3. Goコードの生成

以下のコマンドを実行して、.templ ファイルからGoのコードを生成します。

templ generate

すると、同じディレクトリに hello_templ.go というファイルが生成されます。この中には、hello 関数が templ.Component インターフェースを返すGoのコードが含まれています。

templ.Component は以下のインターフェースを実装しています。

type Component interface {
  Render(ctx context.Context, w io.Writer) error
}

4. Webサーバーでレンダリング

生成されたコンポーネントを net/http を使ってブラウザに返してみましょう。main.go を作成します。

package main

import (
  "fmt"
  "net/http"

  "github.com/a-h/templ"
)

func main() {
  // コンポーネントの初期化
  component := hello("Zenn Reader")

  // templ.Handlerを使ってHTTPハンドラに変換
  http.Handle("/", templ.Handler(component))

  fmt.Println("Listening on :3000")
  http.ListenAndServe(":3000", nil)
}

実行してみましょう。

go run .

ブラウザで http://localhost:3000 にアクセスすると、「Hello, Zenn Reader!」と表示されるはずです!


構文の基本と便利な機能

Templの構文は直感的で、Goを書ける人ならすぐに馴染むことができます。

パッケージ宣言とインポート

.templ ファイルの先頭は、通常のGoファイルと同様にパッケージ名とインポートから始まります。

package main

import "fmt"
import "time"

制御構文(if, switch, for)

テンプレート内でGoの標準的な制御構文をそのまま使用できます。特別なプレフィックスなどは必要ありません。

templ UserProfile(user User) {
  <div class="profile">
    <h1>{ user.Name }</h1>

    if user.IsAdmin {
      <span class="badge badge-admin">Admin</span>
    } else {
      <span class="badge">User</span>
    }

    <ul>
      for _, role := range user.Roles {
        <li>{ role }</li>
      }
    </ul>
  </div>
}

動的な属性とCSSクラスの管理

クラス名を動的に切り替える場合、templ.KV が非常に便利です。templ.KV("クラス名", bool値) の形式で、true のときだけクラスが付与されます。

templ Button(text string, isPrimary bool) {
  <button class={ "btn", templ.KV("btn-primary", isPrimary) }>
    { text }
  </button>
}

スタイル属性でも同様に使えます。

templ TextInput(value string, hasError bool) {
  <input
    type="text"
    value={ value }
    style={
      templ.KV("border-color: #ff3860", hasError),
      templ.KV("background-color: #fff5f7", hasError),
      "padding: 0.5em 1em;",
    }
  >
}

セキュリティ:自動エスケープとURLサニタイズ

Templは、動的な値を自動的にHTMLエスケープします。これにより、XSS(クロスサイトスクリプティング)攻撃を防ぐことができます。

URLも自動でサニタイズされ、javascript: などの危険なプロトコルは about:invalid#TemplFailedSanitizationURL に置き換えられます。

templ component(p Person) {
  // hrefに渡されるURLは自動でサニタイズされる
  <a href={ p.URL }>{ p.Name }</a>
}

サニタイズをバイパスしたい場合は templ.SafeURL() を使いますが、セキュリティリスクが生じる可能性があるため注意が必要です。


コンポーネントの合成(Composition)

Templの真価は、コンポーネントを組み合わせて複雑なUIを構築できる点にあります。

他のコンポーネントを呼び出す

@ 記号を使って、別のコンポーネントを呼び出すことができます。

templ showAll() {
  @left()
  @middle()
  @right()
}

templ left() {
  <div>Left</div>
}

templ middle() {
  <div>Middle</div>
}

templ right() {
  <div>Right</div>
}

子コンポーネントを渡す(Children)

{ children... } を使うことで、ラップするレイアウトコンポーネントを作成できます。

templ Layout(title string) {
  <html>
    <head><title>{ title }</title></head>
    <body>
      <header>My App</header>
      <main>
        { children... }
      </main>
      <footer>© 2026 My App</footer>
    </body>
  </html>
}

templ HomePage() {
  @Layout("Home") {
    <h1>Welcome to the Home Page</h1>
    <p>This is the main content.</p>
  }
}

コンポーネントを引数として渡す

templ.Component 型を引数として受け取ることで、コンポーネントをパラメータとして渡すこともできます。

templ layout(contents templ.Component) {
  <div id="heading">
    <h1>My App</h1>
  </div>
  <div id="contents">
    @contents
  </div>
}

templ paragraph(text string) {
  <p>{ text }</p>
}

templ root() {
  @layout(paragraph("Dynamic contents"))
}

コンポーネントの公開・非公開

Templは、Goの命名規則に従います。大文字で始まるコンポーネントは公開(Public)、小文字で始まるコンポーネントは非公開(Private)です。

// 公開コンポーネント(他パッケージからも使える)
templ PublicHeader(title string) {
  <header><h1>{ title }</h1></header>
}

// 非公開コンポーネント(同パッケージ内のみ)
templ privateFooter() {
  <footer>© 2026</footer>
}

別パッケージのコンポーネントを使う場合は、通常のGoのインポートと同じです。

package main

import "github.com/yourname/yourapp/components"

templ Home() {
  @components.PublicHeader("Welcome")
}

コマンドリファレンス

CLIコマンド一覧

templ コマンドには以下のサブコマンドがあります。

usage: templ <command> [<args>...]

templ - build HTML UIs with Go

commands:
  generate  Generates Go code from templ files
  fmt       Formats templ files
  lsp       Starts a language server for templ files
  info      Displays information about the templ environment
  version   Prints the version
コマンド 説明
templ generate カレントディレクトリ以下の .templ ファイルからGoコードを生成
templ generate -f header.templ 指定したファイルのみGoコードを生成
templ generate -watch ファイルの変更を監視し、保存時に自動再生成
templ fmt . カレントディレクトリ以下の .templ ファイルをフォーマット
templ fmt -fail . フォーマットが必要なファイルがあれば終了コード1で終了(CI向け)
templ lsp Language Serverを起動(通常はエディタ拡張から自動起動)
templ info templ環境の情報を表示
templ version バージョンを表示

templ generate の主要オプション

オプション デフォルト 説明
-path <path> .(カレント) 指定パス以下のファイルを対象にする
-f <file> 単一ファイルのみ生成
-watch false ファイル変更を監視して自動再生成
-cmd <cmd> 生成後に実行するコマンド
-proxy <url> 生成・コマンド実行後にプロキシするURL
-proxyport 7331 プロキシのリッスンポート
-proxybind 127.0.0.1 プロキシのバインドアドレス
-w CPU数 並列ワーカー数
-lazy false .templ.go より新しい場合のみ生成
-v デバッグログを有効化(-log-level debug と同等)
-log-level info ログレベル(debug/info/warn/error
-include-version true 生成コードにtemplバージョンを含めるか
-keep-orphaned-files false 孤立した生成ファイルを保持するか

ライブリロード(開発時の必須コマンド)

開発中は以下のコマンドを使うと非常に快適です。ファイルを保存するたびに自動でコード生成・サーバー再起動・ブラウザリロードが行われます。

templ generate --watch --proxy="http://localhost:8080" --cmd="go run ."

このコマンドは以下を自動で行います。

  • .templ ファイルの変更を検知して自動でGoコードを再生成
  • .go ファイルの変更を検知してWebサーバーを自動再起動
  • localhost:7331 にプロキシを立ち上げ、ブラウザを自動リロード

エディタ設定

VS Code

VS Codeを使用している場合は、公式の拡張機能 「templ」a-h.templ)をインストールするだけで、LSPによる強力なサポートを受けられます。

settings.json に以下の設定を追加することをおすすめします。

保存時の自動フォーマット

{
  "editor.formatOnSave": true,
  "[templ]": {
    "editor.defaultFormatter": "a-h.templ"
  }
}

Tailwind CSS Intellisenseの補完を有効化

{
  "tailwindCSS.includeLanguages": {
    "templ": "html"
  }
}

Emmetの有効化

{
  "emmet.includeLanguages": {
    "templ": "html"
  }
}

Neovim

Neovimでは、nvim-treesitter を使ってシンタックスハイライトを有効化できます。

:TSInstall templ

LSPの設定は lspconfig を使って行います。

local lspconfig = require("lspconfig")

-- Use a loop to conveniently call 'setup' on multiple servers and
-- map buffer local keybindings when the language server attaches
local servers = { 'gopls', 'ccls', 'cmake', 'tsserver', 'templ' }
for _, lsp in ipairs(servers) do
  lspconfig[lsp].setup({
    on_attach = on_attach,
    capabilities = capabilities,
  })
end

-- .templファイルの拡張子を登録(他のLSPが.templを認識するためにも必要)
vim.filetype.add({ extension = { templ = "templ" } })

保存時の自動フォーマットを設定する場合はこちら。

vim.api.nvim_create_autocmd({ "BufWritePre" }, {
  pattern = { "*.templ" },
  callback = vim.lsp.buf.format
})

JetBrains(IntelliJ / GoLand)

JetBrains IDEを使っている方向けのプラグインも提供されています。


まとめ

Templは、Go言語におけるHTMLレンダリングの体験を劇的に向上させるツールです。

  • コンパイル時の型チェックによる安全性
  • コンポーネント指向による高い再利用性
  • LSPサポートによる快適なコーディング体験
  • JavaScript不要でシンプルなアーキテクチャ

これらが揃っているため、特にGoをバックエンドとしたフルスタック開発(htmxなどとの組み合わせ)において、非常に強力な選択肢となります。

標準の html/template で「ちょっと書きづらいな…」と感じたことがある方は、ぜひ一度Templを試してみてください。きっとその快適さに驚くはずです!


参考リンク

VeriCerts Tech Blog

Discussion