Hugo shortcodes are the escape hatch from Markdown: a {{< youtube abc123 >}} in your content becomes whatever layouts/shortcodes/youtube.html says it becomes. They’re also the main reason a generic Markdown editor doesn’t work well for Hugo sites. The editor has no idea what the shortcode means, so it either shows you raw curly braces or, worse, mangles them.
Emet handles two kinds:
- Block shortcodes are the ones you describe in
site.yaml. In the visual editor they become cards with a form for their parameters (or a small chip, if they sit inside a sentence), they can be nested, and the preview pane renders them with an HTML template you provide. - Inline shortcodes are Hugo’s
name.inlinefeature, where the template lives in the content file itself. Emet works out their parameters from the Go template and gives them cards too, with no config needed.
Preview templates covers how both are shown in the preview pane.
What the editor promises#
The visual editor reads every shortcode in a file, in either the {{< >}} or the {{% %}} form, and writes it back in a form Hugo will accept: the same delimiter, a closing tag only where the shortcode had one or needs one, and the same parameter style (positional or named) it came in with. Shortcodes it has no config for are written back exactly as they were read. Escaped shortcodes, shortcodes inside fenced code blocks and shortcodes inside inline code spans are never touched at all.
That used to be less true than it is now. Earlier versions appended a closing tag to everything, which breaks the build for any template that doesn’t read .Inner, and quietly dropped shortcodes in sections that hadn’t opted in. Both are fixed, and there’s a round-trip test in the repository that pins down the shapes Hugo accepts, so if you find one that doesn’t survive a save, that’s where to add it.
Switching on the insert menu#
Shortcodes already in a file are always shown and preserved. What’s optional is the toolbar menu for inserting new ones, which a section has to opt into:
sections:
blog:
folder: content/blog
body:
shortcodes: trueWithout it, the cards are still there and still editable; you just can’t add more from the toolbar. The .inline menu is always present, since inline shortcodes don’t depend on site.yaml.