145

How to insert a cross-reference in a reST/Sphinx page to either a sub-header or anchor in another page in the same documentation set?

bad_coder
  • 11,289
  • 20
  • 44
  • 72
Sue Walsh
  • 1,453
  • 2
  • 10
  • 6
  • Possible duplicate of [How to make an internal hyper link in sphinx documentation](https://stackoverflow.com/questions/4385315/how-to-make-an-internal-hyper-link-in-sphinx-documentation) – Saullo G. P. Castro Sep 27 '17 at 16:47

6 Answers6

249

The expression "reST/Sphinx" makes the scope of the question unclear. Is it about reStructuredText in general and Sphinx, or only about reStructuredText as used in Sphinx (and not reStructuredText in general)? I'm going to cover both since people using RST are likely to run into both cases at some point:

Sphinx

Besides the domain-specific directives that can be used to link to various entities like classes (:class:) there's the general :ref: directive, documented here. They give this example:

    .. _my-reference-label:

    Section to cross-reference
    --------------------------

    This is the text of the section.

    It refers to the section itself, see :ref:`my-reference-label`.

Although the general hyperlinking mechanism offered by RST does work in Sphinx, the documentation recommends against using it when using Sphinx:

Using ref is advised over standard reStructuredText links to sections (like Section title_) because it works across files, when section headings are changed, and for all builders that support cross-references.

RST, in General

The tools that convert RST files to HTML do not necessarily have a notion of collection. This is the case for instance if you rely on github to convert RST files to HTML or if you use a command line tool like rst2html. Unfortunately, the various methods to use to get the desired result vary depending on which tool you are using. For instance, if you use rst2html and you want file A.rst to link to a section named "Section" in file other.rst and you want the final HTML to work in a browser, then A.rst would contain:

`This <other.html#section>`__ is a reference to a section in another
file, which works with ``rst2html``. Unfortunately, it does not work
when the HTML is generated through github.

You have to link to the final HTML file and you have to know what the id given to the section will be. If you want to do the same for a file served through github:

`This <other.rst#section>`__ is a reference to a section in another
file, which works on github. Unfortunately, it does not work when you
use ``rst2html``.

Here too you need to know the id given to the section. However, you link to the RST file because it is only upon accessing the RST file that the HTML is created. (At the time of writing this answer, accessing the HTML directly is not allowed.)

A complete example is available here.

Phlucious
  • 3,704
  • 28
  • 61
Louis
  • 146,715
  • 28
  • 274
  • 320
  • 9
    Much better answer than the one accepted by the question owner. (Despite the fact that `RST, in General`, was disappointing news!) – dlm Jan 06 '14 at 15:48
  • 1
    A disadvantage of the Sphinx `.. _my-reference-label:` approach is that `my-reference-label` is shown in the URL after `#` in the link. So one must use pretty label names. Also, the TOC always creates a `#`-link to `Section to cross-reference`, and thus one ends up with two different `#`-links to the same section. – u17 Jul 06 '17 at 16:35
  • 6
    And if you want to give your link a different name you could always use `:ref:\`Link title \`` – HyperActive Oct 30 '19 at 00:00
71

New, better answer for 2016!

The autosection extension lets you do this easily.

=============
Some Document
=============


Internal Headline
=================

then, later...

===============
Some Other Doc
===============


A link-  :ref:`Internal Headline`

This extension is built-in, so all you need is to edit conf.py

extensions = [
    .
    . other
    . extensions
    . already
    . listed
    .
    'sphinx.ext.autosectionlabel',
]

The only thing you have to be careful of is that now you can't duplicate internal headlines across the doc collection. (Worth it.)

Adam Michael Wood
  • 1,730
  • 16
  • 23
  • 7
    Since I wrote this answer, I have discovered in practice a couple problems with this approach. First, section renaming is a problem. Second, you often have short section titles like "Learn more" or "overview" that you want to use, which you cannot if you are doing this. Solution: add the section title when/if you rename; add a section title for the short section titles (like `_page-title-learn-more`). It's a little annoying, but I still like mostly relying on autosection. – Adam Michael Wood Jun 24 '17 at 13:34
  • 14
    Sphinx 1.6 introduces the [``autosectionlabel_prefix_document`` config option](http://www.sphinx-doc.org/en/stable/ext/autosectionlabel.html#confval-autosectionlabel_prefix_document) which lets you avoid the duplicate headline issue by prefixing each section label with the name of the document it comes from. – smheidrich Sep 07 '17 at 09:27
  • 4
    This is the best solution. And the link title can be easily modified with `:ref:\`Link title \``. Also, you can link directly to a page (quickstart.rst for example) with `:doc:\`quickstart\`` – HyperActive Oct 30 '19 at 02:25
19

Example:

Hey, read the :ref:`Installation:Homebrew` section.

where Homebrew is a section inside a different document named Installation.rst.

This uses the autosection feature, so will need to edit config.py with the following:

extensions = [
    'sphinx.ext.autosectionlabel'
]
autosectionlabel_prefix_document = True
Jano
  • 62,815
  • 21
  • 164
  • 192
  • 2
    In 2.0.0b1 they added `autosectionlabel_maxdepth`, so for autosectionlabel to work you must set that variable to >=`2`. Also, if docs are generated to subdir, like `html`, you must prefix refs with its name: `:ref:'html/Installation:Homebrew'`. For this reason you may want to choose some generic dir name, like `generated`, to make refs less weird looking when used with formats other than HTML. Because of this, you might as well go with `'Homebrew '__` to use proper reST and not being tied to Sphinx. – Pugsley Jan 23 '20 at 12:52
  • I did not need the `html/` prefix – Chris Apr 22 '20 at 23:23
5

In Sphinx 3.0.3 the only solution that worked for me is :any: (see https://www.sphinx-doc.org/en/1.5/markup/inline.html#cross-referencing-anything). Suppose, one document has such a section:

.. _my-section:

My Section
----------

Lorem ipsum blablabla

Then another document can have the following fragment to create a link:

See :any:`my-section` for the details
Paul Lysak
  • 1,284
  • 1
  • 14
  • 18
  • 1
    This is the same as the [top voted answer](https://stackoverflow.com/a/19543591) changing the role. – bad_coder Oct 16 '20 at 19:14
  • @bad_coder the answer you're talking about says nothing about `:any:` – Paul Lysak Oct 20 '20 at 06:41
  • 2
    I suspect you had to use `:any:` because there are 3 dots in your target declaration (should be 2). If the target can be referenced, there's a strong possibility something else is causing the problem. I tried searching for bug reports about `:any:` and `:ref:` roles on [Sphinx's github issue tracker](https://github.com/sphinx-doc/sphinx/issues), but there don't seem to be any matching this description. – bad_coder Oct 20 '20 at 07:21
  • `... _my-section:` is a malformed label. It should be `.. _my-section:`. – mzjn Jul 21 '22 at 10:51
1

Adding description of behavior that was confusing to me.

Section titles must be referenced with the file name (overview here) in front of it:

overview.rst:

    ************
    API Overview
    ************

index.rst:

    :ref:`overview:API Overview`

However, when referencing links, the file name (constants here) must not be there:

constants.rst:

    .. _section-constants:

    *******************
    Enums and Constants
    *******************

api.rst:

    :ref:`section-constants`

Also, for this to work, one must enable extension 'autosectionlabel':

conf.py:

    extensions = [
        ...
        "sphinx.ext.autosectionlabel"
    ]
0

I was struggling to make this work and i found out that the actual notation is :ref:'{dir-path}/Installation:Homebrew' where {dir-path} is the relative path to Installation.rst from where config.py exists