diff --git a/crates/typst-library/src/model/link.rs b/crates/typst-library/src/model/link.rs
index 97307b328..7e8f58756 100644
--- a/crates/typst-library/src/model/link.rs
+++ b/crates/typst-library/src/model/link.rs
@@ -28,14 +28,61 @@ use crate::text::TextElem;
/// ]
/// ```
///
+/// # Syntax
+/// This function also has dedicated syntax: Text that starts with `http://` or
+/// `https://` is automatically turned into a link.
+///
/// # Hyphenation
/// If you enable hyphenation or justification, by default, it will not apply to
/// links to prevent unwanted hyphenation in URLs. You can opt out of this
/// default via `{show link: set text(hyphenate: true)}`.
///
-/// # Syntax
-/// This function also has dedicated syntax: Text that starts with `http://` or
-/// `https://` is automatically turned into a link.
+/// # Links in HTML export
+/// In HTML export, a link to a [label] or [location] will be turned into a
+/// fragment link to a named anchor point. To support this, targets without an
+/// existing ID will automatically receive an ID in the DOM. How this works
+/// varies by which kind of HTML node(s) the link target turned into:
+///
+/// - If the link target turned into a single HTML element, that element will
+/// receive the ID. This is, for instance, typically the case when linking to
+/// a top-level heading (which turns into a single `
` element).
+///
+/// - If the link target turned into a single text node, the node will be
+/// wrapped in a ``, which will then receive the ID.
+///
+/// - If the link target turned into multiple nodes, the first node will receive
+/// the ID.
+///
+/// - If the link target turned into no nodes at all, an empty span will be
+/// generated to serve as a link target.
+///
+/// If you rely on a specific DOM structure, you should ensure that the link
+/// target turns into one or multiple elements, as the compiler makes no
+/// guarantees on the precise segmentation of text into text nodes.
+///
+/// If present, the automatic ID generation tries to reuse the link target's
+/// label to create a human-readable ID. A label can be reused if:
+///
+/// - All characters are alphabetic or numeric according to Unicode, or a
+/// hyphen, or an underscore.
+///
+/// - The label does not start with a digit or hyphen.
+///
+/// These rules ensure that the label is both a valid CSS identifier and a valid
+/// URL fragment for linking.
+///
+/// As IDs must be unique in the DOM, duplicate labels might need disambiguation
+/// when reusing them as IDs. The precise rules for this are as follows:
+///
+/// - If a label can be reused and is unique in the document, it will directly
+/// be used as the ID.
+///
+/// - If it's reusable, but not unique, a suffix consisting of a hyphen and an
+/// integer will be added. For instance, if the label `` exists
+/// twice, it would turn into `mylabel-1` and `mylabel-2`.
+///
+/// - Otherwise, a unique ID of the form `loc-` followed by an integer will be
+/// generated.
#[elem(Locatable)]
pub struct LinkElem {
/// The destination the link points to.