Custom directives
A template file in layouts/directives/ adds a directive. layouts/directives/card.html makes :::card available on every page, rendered by that template. There is nothing to compile, and tryck dev picks up new and changed templates as you save.
Use custom directives for reusable pieces of a page: cards, callouts with a fixed layout, embeds, badges, API boxes.
An example
This site has a card directive. Its template is layouts/directives/card.html:
1<div class="card{{ with .Attrs.class }} {{ . }}{{ end }}"{{ with .Attrs.id }} id="{{ . }}"{{ end }}>
2{{- with .Title }}
3<p class="card-title">{{ with $.Attrs.href }}<a href="{{ relURL . }}">{{ $.Title }}</a>{{ else }}{{ . }}{{ end }}</p>
4{{- end }}
5{{ .Content }}
6</div>
and a few lines of CSS in static/css/docs.css, linked with theme.css. In a page:
Result
Add your own ::: blocks with a template file. Markdown works inside.
Compile plugins into your own tryck binary when a template is not enough.
Markdown
1:::card[Custom directives]{href="/extending/custom-directives/"}
2Add your own `:::` blocks with a template file. **Markdown** works inside.
3:::
4
5:::card[Go plugins]{href="/extending/go-plugins/"}
6Compile plugins into your own tryck binary when a template is not enough.
7:::
Template data
A directive template is a Go html/template, like a layout. It gets:
| Field | Type | Meaning |
|---|---|---|
.Name |
string | The directive name, card. |
.Title |
string | The text in [...], or empty. |
.Attrs |
map of strings | Every attribute in {...}: .Attrs.id from #id, .Attrs.class from .class (several are joined with spaces), and any key=value. A bare name such as {wide} is "true". |
.Content |
HTML | The rendered Markdown body. |
.Site |
SiteInfo | Title, Description, BaseURL, Language, Dev. |
The template functions (relURL, markdownify, default and the others) and your partials are available. Values are escaped for where they appear, so a title or attribute cannot inject HTML.
Unlike the built-in directives, which only pass through a few safe attributes, a template receives all of them. It decides what to output.
Where the body goes
Write {{ .Content }} once, where the body belongs. Everything the template outputs before it comes before the body, and everything after comes after. The body can hold any Markdown, including other directives.
.Contentmust be in the HTML itself, not inside an attribute value..Contentmarks a position; it is not the body as a value. Use it as shown, not inif,lenor other functions.
A template without .Content drops the body, which suits embeds and other self-contained pieces. A YouTube embed, layouts/directives/youtube.html:
1<div class="video">
2<iframe src="https://www.youtube-nocookie.com/embed/{{ .Attrs.id }}" title="{{ default "Video" .Title }}" allowfullscreen loading="lazy"></iframe>
3</div>
1:::youtube[Getting started]{id=dQw4w9WgXcQ}
2:::
Links in attributes
Markdown links in the body are rewritten and checked like any other link. Attribute values are passed as written, so an href attribute takes a site path such as "/extending/go-plugins/". Values with spaces, / or other punctuation need double quotes; single quotes are not accepted. Pass it through relURL in the template so it gets the base path. Links in attributes are not checked.
Where templates are found
Directive templates follow the same lookup as other layouts: a file in the site's layouts/directives/ replaces one with the same name in the theme folder's layouts/directives/. A theme folder can therefore ship directives along with its layouts, and a site can override them one by one.
Names and errors
- The file name is the directive name: letters, digits,
-and_, starting with a letter. - The built-in names (
note,tip,info,warning,danger,detailsandtabs) cannot be replaced; a template with one of them is atemplate.parseerror. - A name rendered by both a template and a Go plugin is a
plugin.configerror. - A template that fails to parse is a
template.parseerror pointing at the template. One that fails while rendering is amarkdown.rendererror on the page that uses it. - A
:::name with no template or plugin renders as a plain<div>with adirective.unknownwarning. Adding the template removes the warning.
See Diagnostics for all codes.