Sphinx Templates
This document explains HTML templating with the Sphinx documentation system. Sphinx is a tool for converting restructured text documentation into presentation formats like HTML or LaTeX.
Sphinx is used for Python documentation (compare old vs. new), but it is great for for any project in any language. Integrated wikis (like Trac) are nice; but I prefer to keep the documentation together with the source code. Sphinx is perfect for that. It also looks like a million bucks.
This document was tested on Fedora 8; however it is likely to work on all platforms that Python supports. Please contact me if you have questions or comments.
Getting Started
First, see the Sphinx documentation and get familiar with installing it (easy_install), initializing a project (sphinx-quickstart), and building your standalone HTML docs (make html).
Notice how (as of right now), the templating documentation is suspiciously missing? That is what this document covers. I spoke with Georg Brandi briefly over email and he said that the document is forthcoming. Therefore I will try to make this page here have a how-to style so that it will hopefully complement the official Sphinx docs when they come out.
The Basics
First, read up on the Django-like Jinja templating system, to get a basic feel for how things work. Just scan through it because you can learn more quickly by experimenting with your own templates.
Your Sphinx templates go in a special subdirectory of your documentation source. By default, this is .templates, so we will use that. (It is set in the templates_path directory in conf.py.) Therefore, all of your template files will go in source/.templates.
Templating with Jinja is all about extending (or inheriting) previously-made templates. So the procedure is to make your own template file and say “this file is mostly like such-and-such template, with these differences….”
Sphinx uses the following built-in template files to generate HTML pages:
- genindex.html
- index.html
- layout.html (This is the main one you want to modify)
- macros.html
- modindex.html
- page.html
- search.html
Making a Template
To modify a template, choose a filename of the template you want to modify and create a file with the same name in .templates. Go ahead! Create .templates/layout.html with some simple content:
{# Filename: .templates/layout.html #}
This is the new layout!
Now run make html to rebuild the HTML. (Note, for Sphinx versions before 0.1.61945, you must run make clean.) Your documentation is gone, but at least you successfully overrode the old layout template!
Extending a Template
We see that you can make a new layout.html to completely override the old layout.html, but how do you merely modify one small part of it? To change just one part of the original Sphinx template, make a new template that extends the old one, and then put a block in your new file. (If you don’t know about extending and blocks, see the Jinja web page.)
Warning: You may try to make a new layout.html that extends the old layout.html. That is wrong:
{# XXX This is wrong! XXX #}
{# Filename: .templates/layout.html #}
{% extends 'layout.html' %}
If you don’t believe me, try it! It will cause an infinite loop when layout.html tries to extend itself. Instead, you must use a Sphinx-specific extension to Jinja by prepending the ! character to the template filename:
{# This is just fine #}
{# Filename: .templates/layout.html #}
{% extends '!layout.html' %}
That’s it! Now you can go crazy making your own blocks that override the old layout template. For example:
{# Filename: .templates/layout.html #}
{% extends '!layout.html' %}
{% block afterfooter %}
Hi! I am beneath the footer.
{% endblock %}
Useful Blocks to Create
Here are some blocks (all in layout.html) that you should start extending. As of this writing, all of these blocks are completely empty in the original layout, so you are not replacing anything, only adding your own content. Therefore they are a good place to experiment.
- extrahead
- beforerelbar, afterrelbar
- beforesidebar1, sidebar1, aftersidebar1
- beforedocument, afterdocument
- beforesidebar2, aftersidebar2
- beforefooter, afterfooter
How To: Add Your Own CSS Stylesheet
To add your own CSS stylesheet, for example, mystyle.css, first create the file in the .static directory. Next, you have a choice depending on what you want to do:
- To use your styles in addition to the defaults, add an “extrahead” block in your own layout.html template, like so:
{# Filename: .templates/layout.html #} {% extends '!layout.html' %} {% block extrahead %} <link rel="stylesheet" href="{{ pathto('_static/mystyle.css', 1) }}" type="text/css" /> {% endblock %} - To completely replace the old styles, replace the html_style variable in conf.py and set it to “mystyle.css”. Of course, you can use @import other styles or do anything else that CSS supports.
How To: Change the “root” page name
I don’t like the default text in the upper-left side of the page. It just says “ProjectName vX.Y documentation” which is pretty boring. To replace it, override the “rootrellink” block in your own template. Here is what I use:
{# Filename: .templates/layout.html #}
{% extends '!layout.html' %}
{% block rootrellink %}
<li>
<a href="{{ pathto('index') }}">FooProject (v{{ release }})</a>
»
</li>
{% endblock %}
How To: Show the current page name in the top navigation bar
I like to show the current page name in the top part of the page, because it provides a kind of “you are here” feel. For example: FooProject » Getting Started » Compiling and Installing
Well, Sphinx builds this for you automatically, except it takes the liberty of deleting the current page from the end of the list! I have no idea why they don’t make it optional, but they just mercilessly chop off the last page from the ancestry list. Here is how you can add it back using templates:
{# Filename: .templates/layout.html #}
{% extends '!layout.html' %}
{% block relbaritems %}
{% if current_page_name != 'index' %}
<li><a href="{{ pathto(current_page_name) }}">{{ title }}</a></li>
{% endif %}
{% endblock %}
How To: Extra Sidebar Content
I like to put extra stuff in the sidebar for every page, however maintaining the html_sidebars variable is tedious. To ensure that every page loads your custom HTML in the sidebar, first create .static/mysidebarcontent.html page with something in it. (Note this file goes in .static, not .templates.)
Next, put this in your layout.html:
{# Filename: .templates/layout.html #}
{% extends '!layout.html' %}
{% set customsidebar = 'mysidebarcontent.html' %}
I know it’s kludgy but it works. You may also want to consider doing this in page.html if you don’t want the custom sidebar stuff on the special index, module index, etc. pages.
Final Comments
Here are some final notes that I have accumulated in no particular order:
- Searching seems to work only if you include the document source. So make sure you set html_copy_source to True in conf.py.
- html_index is not quite intuitive. It does not simply set the Jinja template to use for the index, but rather it activates special handling for the index page. Without it, the index page will build normally using page.html (which extends layout.html). But if you set html_index = “foo.html” for example, then the prefab index.html will run which loads your foo.html inside it in the body (as the indextemplate variable). So remember, index.html is not used unless you set html_index; and if you do set html_index, then your template will merely be rendered as part of the document body. In summary:
- If you want the index page to render using the same template as all the other pages, then you must not set html_index.
- If you want to activate the special template for the index page, you must set html_index in conf.py. The file that you specify will be included in the template.
- If you want to activate the special template and you want to completely override index.html, you must set html_index in conf.py and also create your own index.html in .templates. You will probably want to “extends ‘layout.html’” too. The “indextemplate” variable will be set to whatever you specified in conf.py. To actually render the contents of that file, you must
{{ rendertemplate(indextemplate) }}somewhere in your index.html template.
Posted in Free Software

Wednesday, April 23, 2008 at 4:39 pm
[...] Sphinx Templates | Proven Corporation Blog Wonder why this isn’t in the official Sphinx doc? How to extend or replace the templates that Sphinx uses. (tags: sphinx python templates documentation) [...]