Visual mode

The visual editor is a WYSIWYG editor built on Tiptap, which is a wrapper around ProseMirror. You write, you click buttons, you see formatted text. Under the hood, Emet converts what you see to Markdown on save and back again on load, so the file in your repository is plain Markdown that you could equally well edit in Vim.

That round trip is the interesting part. Most WYSIWYG editors that claim to produce Markdown either produce HTML with a Markdown veneer, or lose things. Emet’s converter knows about GFM tables, task lists, footnotes, definition lists and Hugo shortcodes, and preserves them as the Markdown constructs they are. There are a few things Markdown has no syntax for, covered at the end of this page.

Switching modes#

The Markdown button at the right of the toolbar swaps to the Markdown editor, and the Visual button there brings you back. Your choice is remembered.

The editor.default_mode setting in cms.yaml decides which mode opens first, but only until you switch for the first time; after that your own choice wins.

editor:
  default_mode: visual   # or markdown

The toolbar#

From left to right:

  1. Undo and Redo.
  2. Bold, Italic and Inline code, then a More formatting dropdown with strikethrough, underline, subscript, superscript and highlight.
  3. Link, Image, Quote, a Callout dropdown, Code block and Table.
  4. Dropdowns for Headings (levels 1 to 3), Alignment (left, centre, right, justify), Lists (bullet, numbered, task, definition) and Insert (footnote, horizontal rule).
  5. A Table dropdown that only appears while your cursor is in a table, with add and delete row and column, toggle header row and delete table.
  6. The shortcode menu, if the section allows shortcodes, and the inline shortcode menu.
  7. The AI menu, if a provider is configured and ready.
  8. On the far right, the focus mode toggle and the mode switch.

The schema supports all six heading levels, so an <h4> in an existing file survives the round trip, but the dropdown only offers the three you’re likely to want.

The link button opens a small popover with a URL field, a text field if nothing is selected, and a Remove button when you’re on an existing link. Depending on config it can also show Open in new tab and nofollow checkboxes:

editor:
  links:
    show_new_tab: true
    show_nofollow: true
    default_new_tab: false
    default_nofollow: false

Links with either option set are written as raw HTML <a> tags, because Markdown has no way to express target or rel. The two checkboxes only exist when the site allows raw HTML (see Raw HTML below).

Images#

The image button opens the media library, where you can pick an existing file or upload one. Clicking an image in the editor shows an alt text field underneath it, and an Edit with AI button if image generation is configured.

You can also paste or drop images straight into the editor:

  • One image file opens the media library in save mode, so you can choose the folder and filename before it’s uploaded.
  • Several at once are uploaded in the background with generated names.
  • Images inside pasted rich text (from a web page, say, or a Word document) are imported automatically.

Emet strips blob:, data: and file: image sources before they can reach your Markdown, so a paste that goes wrong leaves a placeholder you can click to fix, rather than a megabyte of base64 in your repository.

Callouts#

The Callout dropdown turns the current paragraph, or the quote you’re in, into a GitHub-style alert: Note, Tip, Important, Warning or Caution. Picking the type the callout already has removes it, and Plain quote keeps the quote but drops the type. In the editor and the preview a callout shows as a coloured box with its label.

A callout is saved as an ordinary Markdown blockquote with a marker line, so it works on sites that don’t allow raw HTML:

> [!WARNING]
> Deleting a user can't be undone.

Emet also keeps the other forms Hugo accepts exactly as you wrote them: lowercase or unknown types such as [!danger], a title after the marker (> [!TIP] Before you start) and the + or - fold sign. The editor shows the title in place of the label, but you can only change it in Markdown mode.

Hugo only styles callouts if your theme or site has a layouts/_markup/render-blockquote.html hook. Many themes ship one; without it Hugo prints a plain quote with the [!WARNING] line in it. See Hugo’s blockquote render hooks for an example.

Code blocks#

A code block has a language dropdown in its top corner. Pick one of the common languages, or Other… to type one that isn’t listed; what you pick becomes the fence’s info string. If you select several paragraphs and click the code block button, they’re merged into one block rather than one block per paragraph.

Tables#

Table inserts a three-by-three table with a header row. There’s no column resizing; the table serialises to a GFM pipe table, which has no widths anyway. Pipe tables can’t do without a header row, so if you toggle it off, Emet writes the table as raw HTML on sites that allow it, and on sites that don’t, it quietly promotes the first row back to a header.

The selection toolbar#

Select some text and a small floating toolbar appears above it with bold, italic, strikethrough, underline, inline code and link. If AI is enabled, there’s also an AI button that opens the inline actions menu: improve, expand, summarise, simplify, rewrite, more formal, more casual, fix grammar and, on multilingual sites, translate. Ctrl+J opens the same menu from the keyboard. See Inline actions.

Focus mode#

The toggle at the right of the toolbar, or Ctrl+. (Cmd+. on a Mac), hides everything except the body editor: sidebar, header, frontmatter, side panels, all gone, with the editor in a centred column. Esc brings it all back. It’s purely a layout change, so nothing is unmounted and your panel state is preserved.

Shortcodes#

Shortcodes in the body render as editable cards instead of raw {{< ... >}} text, or as small chips when they sit inside a sentence, in both the < and % forms. If the entry’s section has body.shortcodes: true and site.yaml defines some, the toolbar also gets a menu for inserting them. The inline shortcode menu is always there, since inline shortcodes are defined in the document itself. See Shortcodes for the whole story, including what Emet does and doesn’t rewrite on save.

What happens to your Markdown#

Opening an entry in visual mode never changes the file. Emet only writes the body back once you edit something, and at that point it converts the whole body from the editor, not just the paragraph you touched. So the first edit to a hand-written file can produce a diff that’s bigger than your change.

A lot is kept as written: plain [text](url) links and their titles, GFM alerts like > [!NOTE], table column alignment, task-list checkboxes, and - bullets and 1. numbers with a single space after the marker.

Some things come out in Emet’s house style instead:

  • * and + bullets become -.
  • _emphasis_ becomes *emphasis*, and __strong__ becomes **strong**.
  • Underlined (setext) headings become # headings.
  • *** and ___ rules become ---.
  • Indented code blocks become fenced ones.
  • Ordered lists are renumbered from their first number.
  • A table cell with several paragraphs is joined onto one line, since pipe tables don’t allow anything else.

If you care about any of those, edit the file in Markdown mode, which saves exactly what you type.

What Markdown can’t say#

Markdown has no syntax for underline, subscript, superscript, highlighting or text alignment, so when you use any of these, Emet writes raw HTML into your Markdown file. Hugo only renders that HTML when the site config sets markup.goldmark.renderer.unsafe = true; with the default setting it drops the whole element from the page, and a build run with --panicOnWarning fails.

Emet therefore reads the Hugo config (or editor.allow_raw_html in cms.yaml, which overrides it) and only offers these controls on sites that allow raw HTML. On other sites the underline, subscript, superscript and highlight entries, the alignment dropdown and their keyboard shortcuts are absent, pasted text loses its alignment and underline styling, and the editor never writes an HTML tag into your content.

Files that already contain raw HTML are not rewritten on load, and Markdown mode leaves them alone. A “Contains raw HTML that Hugo will omit” notice appears in the status bar in both modes so you can tidy up by hand. In visual mode such constructs are shown as plain text, which is what Hugo publishes for that site, so the next edit saves them as plain Markdown. See Raw HTML for the detection rules.

Where next?#