一键导入
templ
Use when creating or editing any Templ (`.templ`) file in this repo.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when creating or editing any Templ (`.templ`) file in this repo.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | templ |
| description | Use when creating or editing any Templ (`.templ`) file in this repo. |
| paths | ["**/*.templ","*.templ"] |
Three parts: parser gotchas that apply to every .templ file, the naming rule for wrapper Opts fields, and the conventions for component doc pages and their playgrounds.
Inside .templ element content, the words for, if, switch, case, default, else, range are parsed as control-flow keywords when one is the first token on a line (ignoring leading whitespace): <p>X to do.\n\tfor a Y</p>. Mid-line is fine, even right after an inline tag close (<p>add <code>flag</code> for the Y</p> parses).
Symptom: expected nodes, but none were found: line N, col M, often pointing at EOF.
Make sure Go keywords aren't the first token in a template line.
= / " inside <code><code>foo="bar"</code> is parsed as a <code> tag with attribute foo="bar" and breaks the same way. Wrap with backticks: <code>{ foo="bar" }</code>.
A wrapper Opts field has the same name as the custom-element attribute it sets, exported (PascalCase, since it's Go) and typed Attr[T]. Use the most specific type, not Attr[string]: a named enum for a fixed set of values, CSSUnit for a CSS length, int for a whole number (count, index, ms delay), float64 for a value that can be fractional (a slider value/min/max/step).
touch becomes Touch Attr[bool]align becomes Align Attr[CarouselAlign]spacing becomes Spacing Attr[CSSUnit]page becomes Page Attr[int]For a layout-axis field, type it Attr[Axis] when the component supports only horizontal and vertical, or Attr[Orientation] when it also supports grid (e.g. navgroup, sortable). Using Axis keeps an unsupported grid unrepresentable.
How component doc pages (internal/site/page_*.templ) are written.
Page structure, in order:
Rules:
[data-neo-*] hooks. Not the @neo.* / datastar.* helper.Component <code>{ "<neo-foo>" }</code> is ….anchoredH3 demo; if a note needs "and also…", split it.foo, Variant A).internal/site/examples/<name>.templ. The *_demo.go renders it for the HTML tab and embeds the file verbatim for the Templ tab (//go:embed examples/<name>.templ); the page passes both as HTML source and Templ source and renders @examples.X() as the live preview. One source drives all three. Keep no separate .html, hard-coded const strings, or Go-built (string concat) HTML var for an example.@… calls allowed are the @neo.* wrappers the example demonstrates). Allowed (all visible in the same file): a helper templ func defined in this file (e.g. a recursive templ treeNode(...) for arbitrary-depth nesting, or a templ.Component value the wrapper API requires), a local type/data var, and for loops over inline data. Prefer copying markup/CSS over factoring it out; reach for a same-file helper only when structure forces it (recursion, a component-valued option)..templ files with TABS, including inside <style> blocks (one tab per CSS nesting level). The HTML-tab pretty-printer converts those tabs to two spaces; space indentation in the source yields ragged output.<p class="demo-note"> above each demo):
Disabled options: …).<p class="demo-note">.<p class="demo-note"> + a
<ul class="demo-note"> (never a one-item list).ComponentDoc Description):
<neo-popover> → Popover page).New or migrated overview pages use the reusable Playground Templ component (internal/site/playground.templ), driven by the site-only <site-playground> controller (web/site/site-playground.ts). No per-page playground scripts, simulator routes, or one-off editors.
Default. Other states reuse the real examples already on the page, with no placeholders like Variant A.data-signals (double-quoted attribute, unquoted keys, single-quoted strings: data-signals="{foo_bar: 1, baz: 'x'}"), and drive the markup with normal Datastar bindings. Controls handle scalar string, number, boolean, and null. Namespace signal names to the component/page.checked, pressed, open) needs the command-string form plus a synchronous write-back, not a bare boolean: data-attr:checked="$sig ? 'true' : 'false'" with data-on:neo-<tag>-change="$sig = evt.detail.checked". A bare data-attr:checked="$sig" makes Datastar remove the attribute on false, which the component reads as "no command, keep current state" (DESIGN.md Attribute Contract), so the control snaps back and stays visually on until a second interaction. Canonical examples: checkbox_default.html, sidebar_default.html.PlaygroundOpts.Height only when the component needs a fixed canvas.