NanoFile

Markdown internal links

There is no special syntax for an internal link. It is an ordinary link whose target is a heading in the same document, a file next to it, or a heading in that file. What makes it fragile is that nobody writes the anchor: the renderer derives it from your heading text.

To a heading in this document

See the installation steps below.

Installation steps

The anchor is the heading, lowercased, with punctuation dropped and spaces turned into dashes.

To another file, and to a heading in it
An anchor you control

A heading that may be reworded

A link that will not break

Renderers that allow HTML honour the id. Ones that strip HTML do not, so this is a repository trick rather than a portable one.

The anchor is derived, which is why it breaks

You do not choose an anchor. The renderer takes the heading text, lowercases it, drops the punctuation, turns each space into a dash, and that is the anchor. Reword the heading and every link to it stops working, silently: the page still loads and the browser simply does not scroll.

Two headings with the same text produce the same anchor, so renderers number the second one. #setup and #setup-1 are the same words in the same document, and which one is which depends on the order they appear in.

A link between files is resolved by whatever is showing them

[guide](docs/guide.md) works on GitHub because GitHub is showing you a directory. It breaks in a documentation site that turned docs/guide.md into /guide/, and it breaks in any viewer that was handed one file rather than a folder. This is the same problem relative images have, and it has the same answer: an absolute URL where the document has to travel, relative paths where it does not.

What to do about it

Check them. The checker on this site reports a link to an anchor that nothing in the document produces, and the repository checker does it across every markdown file in a repo. Neither can tell you whether a link to another file resolves, because that depends on where the file ends up.

What usually goes wrong

  • Reword a heading and every link to it breaks, without any error. The page loads and nothing scrolls.
  • Emoji, code spans and links inside a heading all change the anchor. What you see is not what the anchor is made of.
  • A second heading with the same text gets a numbered anchor, so #setup-1 may be the one you meant.
  • A link to a file that has moved cannot be detected by any checker, because nothing in the document says where the file was supposed to be.

Where it behaves differently

It renders as written on GitHub, GitLab and VS Code preview. Everywhere else in this table it does something else, and that is worth reading before you paste.

PlatformBehaviour
ObsidianAlso [[Note#Heading]], which links to a heading in another note.
NotionNot supported. The syntax arrives as its own punctuation.
DiscordNot supported. The syntax arrives as its own punctuation.
SlackNot supported. The syntax arrives as its own punctuation.

Questions

How do I find the anchor for a heading?

On GitHub, hover the heading and copy the link that appears. Otherwise use the contents generator on this site: it produces the anchors GitHub produces, for the whole document at once.

Can I set my own anchor?

In a renderer that allows HTML, yes: an empty element with an id, just before the heading. It is not portable, so it is worth it for a heading you expect to reword and not much else.

Do these anchors work outside GitHub?

GitLab, Bitbucket and most static site generators use the same slug. A few prefix every id for safety, and then links need the prefix too. This site's exported HTML does exactly that, and says so on the contents generator's page.

Related

For the .md file that arrives in Mail

Not released yet

A markdown file on a phone is the worst case: no editor, no preview, and a share sheet full of apps that want to import it into a library. The iPhone and iPad app opens it where it landed, renders it, and lets you edit and save it back.

For iPhone and iPad. It is not in the App Store, so there is nothing to download from this page yet.Digital Sandbox, who are building it →