How to customise the styling of em-dashes in Typst

Today I learnt …

Use a simple ‘show rule’ to style em-dashes with no extra markup and no interruptions to your writing flow

Typst is a modern, markup-based typesetting system designed as a successor to LaTeX. If you need to produce PDFs — particularly for academic or technical writing — then it’s an invaluable tool.

Writing in Typst is much like writing in Markdown: you write primarily in plain-text, adding lightweight markup only when you need it — _italics_, *bold text*, that sort of thing. It stays out of your way when you just want to write.

I am, however, quite particular about formatting. Take em-dashes, for example. I prefer them flanked by narrow non-breaking spaces. Narrow, so they don’t butt up directly against surrounding words, yet aren’t surrounded by oceans of whitespace. Non-breaking, so they don’t end up orphaned at the end of a line.

The problem? Typing this needs markup, which takes me out of the flow of writing. To produce the following sentence:

The food — which was delicious — reminded me of Morocco

I’d need to write each em-dash as:

\u{202F}#sym.dash.em\u{202F}

Which is unreadable, tedious, and prone to mistakes. What I really want is to write it in a way that allows me to keep typing without thinking about typesetting. Typst has a shortcut for an em-dash (three hyphens, ---). I want to type that but get my surrounding narrow-width non-breaking spaces too. I want to type this:

The food --- which was delicious --- reminded me of Morocco

And have it render as:

The food\u{202F}#sym.dash.em\u{202F}which was delicious\u{202F}#sym.dash.em\u{202F}reminded me of Morocco

Yesterday, I had a eureka moment: I realised I can use Typst’s show rules to do exactly that. Below is a show rule with a text selector, " — " (space, em-dash, space), that replaces that text with an em-dash surrounded by narrow non-breaking spaces:

#show " — ": [\u{202F}#sym.dash.em\u{202F}]

The trick is that the text selector, " — ", should match the rendered text (an em-dash character) and not the written text (---).

Typst’s show rules are incredibly powerful. With show regex("...") I should also be able to render acronyms and initialisms in small-caps without having to wrap each instance in smallcaps(). That’s next on my to-do list.