Material for MkDocs
A Material Design theme for MkDocs
Copyright © 2016 - 2020 Martin Donath
Copyright © 2016 - 2020 Martin Donath
Material for MkDocs is a theme for MkDocs, a static site generator geared
towards (technical) project documentation. If you're familiar with Python, you can install Material for MkDocs
with pip
, the Python package manager. If not, we
recommended using docker
.
In case you're running into problems, consult the troubleshooting section.
Material for MkDocs can be installed with pip
:
pip install mkdocs-material
pip install git+https://${GH_TOKEN}@github.com/squidfunk/mkdocs-material-insiders.git
This will automatically install compatible versions of all dependencies: MkDocs, Markdown, Pygments and Python Markdown Extensions. Material for MkDocs always strives to support the latest versions, so there's no need to install those packages separately.
Note that in order to install Material for MkDocs Insiders, you'll need to become a sponsor, create a personal
access token1, and set the GH_TOKEN
environment
variable to the token's value.
The official Docker image is a great way to
get up and running in a few minutes, as it comes with all dependencies pre-installed. Pull the image for the
latest
version with:
docker pull squidfunk/mkdocs-material
The mkdocs
executable is provided as an entry point and serve
is the default
command. If you're not familiar with Docker don't worry, we have you covered in the following sections.
The following plugins are bundled with the Docker image:
Material for MkDocs can be directly used from GitHub by cloning the repository into a subfolder of your project root which might be useful if you want to use the very latest version:
git clone https://github.com/squidfunk/mkdocs-material.git
git clone git@github.com:squidfunk/mkdocs-material-insiders.git mkdocs-material
The theme will reside in the folder mkdocs-material/material
. When cloning from
git
, you must install all required dependencies yourself:
pip install -r mkdocs-material/requirements.txt
Note that in order to install Material for MkDocs Insiders, you'll need to become a sponsor.
In order to use pip
to install from the private repository over HTTPS, the personal access
token requires the repo
scope. The creation and usage of an access token is only necessary when installing Insiders over HTTPS,
which is the recommended way when building from within a CI/CD workflow, e.g. using GitHub Pages or GitLab Pages. ↩
After you've installed Material for MkDocs, you can bootstrap your project
documentation using the mkdocs
executable. Go to the directory where you want your project to be
located and enter:
mkdocs new .
Alternatively, if you're running Material for MkDocs from within Docker, use:
docker run --rm -it -v ${PWD}:/docs squidfunk/mkdocs-material new .
docker run --rm -it -v "%cd%":/docs squidfunk/mkdocs-material new .
This will create the following structure:
.
├─ docs/
│ └─ index.md
└─ mkdocs.yml
Depending on your installation method, you can now add the
following lines to mkdocs.yml
in your project root. If you installed Material for MkDocs using
pip
or docker
, add:
theme:
name: material
If you cloned Material for MkDocs from GitHub, add:
theme:
name: null
custom_dir: mkdocs-material/material
Material for MkDocs comes with a lot of configuration options. The setup section explains in great detail how to configure and customize colors, fonts, icons and much more:
MkDocs includes a live preview server, so you can preview your changes as you write your documentation. The server will automatically rebuild the site upon saving. Start it with:
mkdocs serve
If you're running Material for MkDocs from within Docker, use:
docker run --rm -it -p 8000:8000 -v ${PWD}:/docs squidfunk/mkdocs-material
docker run --rm -it -p 8000:8000 -v "%cd%":/docs squidfunk/mkdocs-material
Point your browser to localhost:8000 and you should see:
When you're finished editing, you can build a static site from your Markdown files with:
mkdocs build
The contents of this directory make up your project documentation. There's no need for operating a database or server, as it is completely self-contained. The site can be hosted on GitHub Pages, GitLab Pages, a CDN of your choice or your private web space.
The great thing about hosting project documentation in a git
repository is the ability to deploy
it automatically when new changes are pushed. MkDocs makes this ridiculously simple.
If you're already hosting your code on GitHub, GitHub Pages is certainly the most convenient way to publish your project documentation. It's free of charge and pretty easy to set up.
Using GitHub Actions you can automate the deployment of
your project documentation. At the root of your repository, create a new GitHub Actions workflow, e.g.
.github/workflows/ci.yml
, and copy and paste the following contents:
name: ci
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: 3.x
- run: pip install mkdocs-material
- run: mkdocs gh-deploy --force
name: ci
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: 3.x
- run: pip install git+https://${GH_TOKEN}@github.com/squidfunk/mkdocs-material-insiders.git
- run: mkdocs gh-deploy --force
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
Now, when a new commit is pushed to master
, the static site is automatically built and deployed.
Commit and push the file to your repository to see the workflow in action.
Your documentation should shortly appear at <username>.github.io/<repository>
.
Remember to set the GH_TOKEN
environment variable to the value of your personal
access token when using Material for MkDocs Insiders, which can be done
using secrets.
If you prefer to deploy your project documentation manually, you can just invoke the following command from
the directory containing the mkdocs.yml
file:
mkdocs gh-deploy --force
If you're hosting your code on GitLab, deploying to GitLab Pages can
be done by using the GitLab CI task runner. At the root of your
repository, create a task definition named .gitlab-ci.yml
and copy and paste the following
contents:
image: python:latest
deploy:
stage: deploy
only:
- master
script:
- pip install mkdocs-material
- mkdocs build --site-dir public
artifacts:
paths:
- public
image: python:latest
deploy:
stage: deploy
only:
- master
script:
- pip install git+https://${GH_TOKEN}@github.com/squidfunk/mkdocs-material-insiders.git
- mkdocs build --site-dir public
artifacts:
paths:
- public
Now, when a new commit is pushed to master
, the static site is automatically built and deployed.
Commit and push the file to your repository to see the workflow in action.
Your documentation should shortly appear at <username>.gitlab.io/<repository>
.
Remember to set the GH_TOKEN
environment variable to the value of your personal
access token when using Material for MkDocs Insiders, which can be done
using masked custom
variables.
Project documentation is as diverse as the projects themselves and Material for MkDocs is a great starting point for making it look beautiful. However, as you write your documentation, you may reach a point where small adjustments are necessary to preserve your brand's style.
MkDocs provides several ways to customize a theme. In order to make a
few tweaks to Material for MkDocs, you can just add your stylesheets and JavaScript files to the
docs
directory.
If you want to tweak some colors or change the spacing of certain elements, you can do this in a separate
stylesheet. The easiest way is by creating a new stylesheet file in the docs
directory:
.
├─ docs/
│ └─ stylesheets/
│ └─ extra.css
└─ mkdocs.yml
Then, add the following line to mkdocs.yml
:
extra_css:
- stylesheets/extra.css
Spin up the live preview server and start typing your changes in your additional stylesheet file – you should see them almost instantly after saving.
The same is true for additional JavaScript. If you want to integrate another syntax highlighter or add some
custom logic to your theme, create a new JavaScript file in the docs
directory:
.
├─ docs/
│ └─ javascripts/
│ └─ extra.js
└─ mkdocs.yml
Then, add the following line to mkdocs.yml
:
extra_javascript:
- javascripts/extra.js
Further assistance can be found in the MkDocs documentation.
If you want to alter the HTML source (e.g. add or remove some parts), you can extend the theme. MkDocs supports theme extension, an easy way to override parts of Material for MkDocs without forking from git. This ensures that you can update to the latest version more easily.
Enable Material for MkDocs as usual in mkdocs.yml
, and create a new folder for
overrides
which you then reference using the custom_dir
key:
theme:
name: material
custom_dir: overrides
Theme extension prerequisites
As the custom_dir
variable is used for the theme extension process, Material for MkDocs needs
to be installed via pip
and referenced with the name
parameter in
mkdocs.yml
. It will not work when cloning from git
.
The structure in the overrides
directory must mirror the directory structure of the original
theme, as any file in the overrides
directory will replace the file with the same name which is
part of the original theme. Besides, further assets may also be put in the overrides
directory.
The directory layout of the theme is as follows:
.
├─ .icons/ # Bundled icon sets
├─ assets/
│ ├─ images/ # Images and icons
│ ├─ javascripts/ # JavaScript
│ └─ stylesheets/ # Stylesheets
├─ partials/
│ ├─ integrations/ # Third-party integrations
│ │ ├─ analytics.html # - Google Analytics
│ │ └─ disqus.html # - Disqus
│ ├─ language/ # Localized languages
│ ├─ footer.html # Footer bar
│ ├─ header.html # Header bar
│ ├─ hero.html # Hero teaser
│ ├─ language.html # Localized labels
│ ├─ logo.html # Logo in header and sidebar
│ ├─ nav.html # Main navigation
│ ├─ nav-item.html # Main navigation item
│ ├─ palette.html # Color palette
│ ├─ search.html # Search box
│ ├─ social.html # Social links
│ ├─ source.html # Repository information
│ ├─ source-date.html # Last updated date
│ ├─ source-link.html # Link to source file
│ ├─ tabs.html # Tabs navigation
│ ├─ tabs-item.html # Tabs navigation item
│ ├─ toc.html # Table of contents
│ └─ toc-item.html # Table of contents item
├─ 404.html # 404 error page
├─ base.html # Base template
└─ main.html # Default page
In order to override a partial, we can replace it with a file of the same name and location in the
overrides
directory. For example. to replace the original footer.html
, create a
footer.html
file in the overrides/partials
directory:
.
├─ overrides/
│ └─ partials/
│ └─ footer.html
└─ mkdocs.yml
MkDocs will now use the new partial when rendering the theme. This can be done with any file.
Besides overriding partials, it's also possible to override (and extend) template blocks, which are
defined inside the templates and wrap specific features. To override a block, create a main.html
file inside the overrides
directory:
.
├─ overrides/
│ └─ main.html
└─ mkdocs.yml
Then, e.g. to override the site title, add the following line to main.html
:
{% extends "base.html" %}
{% block htmltitle %}
<title>Lorem ipsum dolor sit amet</title>
{% endblock %}
Material for MkDocs provides the following template blocks:
Block name | Wrapped contents |
---|---|
analytics |
Wraps the Google Analytics integration |
announce |
Wraps the announcement bar |
config |
Wraps the JavaScript application config |
content |
Wraps the main content |
disqus |
Wraps the Disqus integration |
extrahead |
Empty block to add custom meta tags |
fonts |
Wraps the font definitions |
footer |
Wraps the footer with navigation and copyright |
header |
Wraps the fixed header bar |
hero |
Wraps the hero teaser (if available) |
htmltitle |
Wraps the <title> tag |
libs |
Wraps the JavaScript libraries (header) |
scripts |
Wraps the JavaScript application (footer) |
source |
Wraps the linked source files |
site_meta |
Wraps the meta tags in the document head |
site_nav |
Wraps the site navigation and table of contents |
styles |
Wraps the stylesheets (also extra sources) |
tabs |
Wraps the tabs navigation (if available) |
For more on this topic refer to the MkDocs documentation.
Material for MkDocs uses Webpack as a build tool to leverage modern web technologies like TypeScript and SASS. If you want to make more fundamental changes, it may be necessary to make the adjustments directly in the source of the theme and recompile it.
In order to start development on Material for MkDocs, a Node.js version of at least 12 is required. First, clone the repository:
git clone https://github.com/squidfunk/mkdocs-material
Next, all dependencies need to be installed, which is done with:
cd mkdocs-material
pip install -r requirements.txt
pip install mkdocs-minify-plugin
npm install
Start the Webpack watchdog with:
npm start
Then, in a second session, start the MkDocs server with:
mkdocs serve
Point your browser to localhost:8000 and you should see this documentation in front of you.
Automatically generated files
Never make any changes in the material
directory, as the contents of this directory are
automatically generated from the src
directory and will be overridden when the theme is built.
When you're finished making your changes, you can build the theme by invoking:
npm run build
This triggers the production-level compilation and minification of all stylesheets and JavaScript sources.
When the command exits, the final files are located in the material
directory. Add the
theme_dir
variable pointing to the aforementioned directory in the original
mkdocs.yml
.
Now you can run mkdocs build
and you should see your documentation with your changes to the
original theme.
Operating systems:
Error: Unrecognized theme
mkdocs serve
# => INFO - Building documentation...
# => ERROR - Config value: 'theme'. Error: Unrecognised theme 'material'.
# => ...
# => ConfigurationError: Aborted with 1 Configuration Errors!
If you run into this error, the most common reason is that you installed MkDocs through some package manager
(e.g. brew
or apt-get
) and Material for MkDocs through pip
, so both
packages end up in different locations. MkDocs only checks its install location for themes.
Operating systems:
Error: Permission denied
pip install mkdocs-material
# => Could not install packages due to an EnvironmentError: [Errno 13] Permission denied: '...'
# => Consider using the --user option or check the permissions.
When you're running the pre-installed version of Python on macOS, pip
tries to install packages
in a folder for which your user might not have the adequate permissions. There are three possible solutions
for this, the recommended one of which is to use virtual environments:
If you're installing Material for MkDocs with pip
, the easiest way to make sure that you
end up with the correct versions and without any incompatibility problems between packages it to use a
virtual environment. First, ensure that you
have a Python version of 3 or higher installed:
python --version
If you're good to go, create and activate a virtual environment with:
python -m venv venv
source ./venv/bin/activate
Note that the second venv
is the name of the folder where to create the virtual
environment – you may choose it as you like. Your terminal should now print (venv)
before
the prompt and the python
executable should be located inside the folder you just created.
Next, install Material for MkDocs with pip
, which
will download and install all packages in the venv
folder you just created, including
MkDocs and its dependencies:
pip install mkdocs-material
Verify that MkDocs and Material for MkDocs were both installed correctly:
mkdocs --version
mkdocs serve --help
MkDocs should list material
as an option under the --theme
flag. When you're
finished working with MkDocs, you can exit the virtual environment with:
deactivate
Provide the --user
flag to the install command and pip
will install the
package in a user-site location. While this is not a global installation, it's still not isolated and
may lead to problems when you use different versions of Material for MkDocs in other projects:
pip install --user mkdocs-material
Upgrade your Python installation by installing Python with Homebrew.
This should eliminate a lot of problems you will run into with pip
. Yet, it's still not an
isolated installation which may also lead to the same problems as installing in user space:
brew upgrade python
In itself, Material for MkDocs does not perform any tracking and should adhere to the General Data Protection Regulation (GDPR), but it integrates with some third-party services that may not.
Material for MkDocs makes fonts configurable by relying on Google
Fonts CDN, which may be in breach with GDPR. The usage of Google's CDN can be easily disabled via mkdocs.yml
.
Material for MkDocs comes with optional Google Analytics and Disqus integrations, both of which must be enabled explicitly, so there's no immediate action if you don't use those.
Material for MkDocs uses the sponsorware release strategy, which means that new features are first exclusively released to sponsors as part of Material for MkDocs Insiders. Read on to learn how sponsorship works, and how you can become a sponsor.
A demo is worth a thousand words — check it out at
squidfunk.github.io/mkdocs-material-insiders
New features will first land in Material for MkDocs Insiders, which means that sponsors will have access immediately. Every feature is tied to a funding goal in monthly subscriptions. If a funding goal is hit, the features that are tied to it are merged back into Material for MkDocs and released for general availability. Bugfixes will always be released simultaneously in both editions.
See the roadmap for a list of already available and upcoming features, and for demonstration purposes, the official documentation built with Material for MkDocs Insiders.
So you've decided to become a sponsor? Great! You're just three easy steps away from enjoying the latest features of Material for MkDocs Insiders. Complete the following steps and you're in:
Congratulations! You're now officially a
sponsor and will get updates for Material for MkDocs Insiders, until you decide to cancel your monthly
subscription, which you can do at any time.
The following list of funding goals – named after varieties of chili peppers I'm growing on my balcony – shows which features are already available in Material for MkDocs Insiders.
Funding goal: $500 · Status: exclusive
New features and improvements for search, including:
Funding goal: $1,000 · Status: exclusive
New features and improvements for content and toc, including:
Funding goal: $1,500 · Status: exclusive
New features and improvements for hosting multiple versions, including:
Funding goal: $2,000 · Status: exclusive
New features and improvements for user preferences, including:
Funding goal: $3,000 · Status: exclusive
Alternative, completely different vertical layout, optimized to read documentation and code side-by-side, e.g. for the documentation of APIs with the same functionality as Material for MkDocs.
We're running an open source project and want to make sure that users can build the documentation without having access to Insiders. Is that still possible?
Yes. Material for MkDocs Insiders strives to be compatible with Material for MkDocs, so all new features are
implemented as feature flags and all improvements (e.g. search) do not require any changes to existing
configuration. This means that your users will be able to build the docs locally with the regular version and
when they push their changes to CI/CD, they will be built with Material for MkDocs Insiders. For this reason,
it's recommended to install Insiders only in CI, as you
don't want to expose your GH_TOKEN
to users.
We're using Material for MkDocs to build the developer documentation of a commercial project. Can we use Material for MkDocs Insiders under the same terms?
Yes. Whether you're an individual or a company, you may use Material for MkDocs Insiders precisely under the same terms as Material for MkDocs, which are given by the MIT license. However, we kindly ask you to respect the following guidelines:
Please don't distribute the source code from Material for MkDocs Insiders. You may freely use it for public, private or commercial projects, fork it, mirror it, do whatever you want with it, but please don't release the source code, as it would cannibalize the sponsorware strategy.
If you cancel your subscription, you're removed as a collaborator and will miss out on future updates of Material for MkDocs Insiders. However, you may use the latest version that's available to you as long as you like. Just remember that GitHub deletes private forks.
MIT License
Copyright © 2016-2020 Martin Donath martin.donath@squidfunk.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
As any proper Material Design implementation, Material for MkDocs supports Google's original color palette, which can be easily configured through
mkdocs.yml
. Furthermore, colors can be customized with a few lines of CSS to fit your brand's
identity by using CSS variables.
Source · Default: default
Material for MkDocs supports two color schemes: a light mode, which is just called
default
, and a dark mode, which is called slate
. The color scheme can be set via
mkdocs.yml
:
theme:
palette:
scheme: default
Click on a tile to change the color scheme:
The color scheme can also be set based on user preference, which makes use of the
prefers-color-scheme
media query, by setting the value in mkdocs.yml
to
preference
:
theme:
palette:
scheme: preference
Source · Default: indigo
The primary color is used for the header, the sidebar, text links and several other components. In
order to change the primary color, set the following value in mkdocs.yml
to a valid color name:
theme:
palette:
primary: indigo
Click on a tile to change the primary color:
Source · Default: indigo
The accent color is used to denote elements that can be interacted with, e.g. hovered links, buttons
and scrollbars. It can be changed in mkdocs.yml
by choosing a valid color name:
theme:
palette:
accent: indigo
Click on a tile to change the accent color:
Accessibility – not all color combinations work well
With 2 (color schemes) x 21 (primary colors) x 17 (accent color) = 714 combinations, it's impossible to ensure that all configurations provide a good user experience (e.g. yellow on light background). Make sure that the color combination of your choosing provides enough contrast and tweak CSS variables where necessary.
Source · Experimental · Insiders only
Material for MkDocs Insiders makes it possible to define multiple color palettes,
including a scheme, primary and accent color each, and let the user choose. Define them
via mkdocs.yml
:
theme:
palette:
- scheme: default
primary: indigo
accent: indigo
toggle:
icon: material/toggle-switch
name: Switch to light mode
- scheme: slate
primary: blue
accent: blue
toggle:
icon: material/toggle-switch-off-outline
name: Switch to dark mode
The toggle
field allows to specify an icon
and name
for each palette.
The toggle is rendered next to the search bar and will cycle through all defined color palettes:
icon
Default: none · Required – This field must point to a valid icon path referencing any icon bundled with the theme, or the build will not succeed. Some popular combinations:
material/toggle-switch-off-outline
+ material/toggle-switch
material/weather-sunny
+ material/weather-night
material/eye-outline
+ material/eye
material/lightbulb-outline
+ material/lightbulb
name
Default: none · Required – This field is used as the toggle's title
attribute and should be
set to a discernable name to improve accessibility.
Give this feature a try on the official documentation built with Material for MkDocs Insiders!
Source · Difficulty: easy
Material for MkDocs implements colors using CSS variables (custom properties). If you want to customize the colors beyond the palette (e.g. to use your brand-specific colors), you can add an additional stylesheet and tweak the values of the CSS variables.
Let's say you're YouTube, and want to set the primary color to your brand's palette. Just add:
:root {
--md-primary-fg-color: #EE0F0F;
--md-primary-fg-color--light: #ECB7B7;
--md-primary-fg-color--dark: #90030C;
}
See the file containing the color definitions for a list of all CSS variables.
Source · Difficulty: easy
Besides overriding specific colors, you can create your own, named color scheme by wrapping the definitions
in the [data-md-color-scheme="..."]
attribute selector, which you can then
set via mkdocs.yml
as described in the color
schemes section:
[data-md-color-scheme="youtube"] {
--md-primary-fg-color: #EE0F0F;
--md-primary-fg-color--light: #ECB7B7;
--md-primary-fg-color--dark: #90030C;
}
Additionally, the slate
color scheme defines all of it's colors via hsla
color
functions and deduces its colors from the --md-hue
CSS variable. You can tune the
slate
theme with:
[data-md-color-scheme="slate"] {
--md-hue: 210; /* [0, 360] */
}
Material for MkDocs makes it easy to change the typeface of your project documentation, as it directly integrates with Google Fonts. Alternatively, fonts can be custom-loaded if self-hosting is preferred for data privacy reasons or another destination should be used.
The regular font is used for all body copy, headlines, and essentially everything that does not need to be proportionally spaced. It can be set to any valid Google Font with:
theme:
font:
text: Roboto
The typeface will be loaded in 300, 400, 400i and 700.
Source · Default: Roboto Mono
The proportional font is used for code blocks and can be configured separately. Just like the
regular font, it can be set to any valid Google Font via
mkdocs.yml
with:
theme:
font:
code: Roboto Mono
The typeface will be loaded in 400.
If you want to load fonts from other destinations or don't want to use Google Fonts for data privacy reasons, e.g. due to GDPR, you may customize font loading as described below.
Source · Difficulty: easy
If you want to prevent typefaces from being loaded from Google Fonts and fall back to system fonts, add the
following lines to mkdocs.yml
:
theme:
font: false
Source · Difficulty: easy
If you want to load an (additional) font from another or override the fallback font, you can use an additional stylesheet to add the corresponding
@font-face
definition:
@font-face {
font-family: "<font>";
src: "...";
}
The font can then be applied to specific elements, e.g. only headlines, or globally to be used as the site-wide regular or proportional font:
body, input {
font-family: "<font>", -apple-system, Helvetica, Arial, sans-serif;
}
pre, code, kbd {
font-family: "<font>", SFMono-Regular, Consolas, Menlo, monospace;
}
Material for MkDocs supports internationalization (i18n) and provides translations for template variables and labels in 40+ languages. Additionally, the site search can be configured to use a language-specific stemmer (if available).
Source · Default: en
You can set the site language in mkdocs.yml
with:
theme:
language: en
The following languages are supported:
af
– Afrikaansar
– Arabicbn
– Bengali (Bangla)ca
– Catalancs
– Czechda
– Danishde
– Germanen
– Englisheo
– Esperantoes
– Spanishet
– Estonianfa
– Persian (Farsi)fi
– Finnishfr
– Frenchgl
– Galiciangr
– Greekhe
– Hebrewhi
– Hindihr
– Croatianhu
– Hungarianid
– Indonesianit
– Italianja
– Japanesekr
– Koreanmy
– Burmesenl
– Dutchnn
– Norwegian (Nynorsk)no
– Norwegianpl
– Polishpt
– Portuguesero
– Romanianru
– Russiansh
– Serbo-Croatiansi
– Sloveniansk
– Slovaksr
– Serbiansv
– Swedishth
– Thaitr
– Turkishuk
– Ukrainianvi
– Vietnamesezh
– Chinese (Simplified)zh-Hant
– Chinese (Traditional)zh-TW
– Chinese (Taiwanese)Note that some languages will produce unreadable anchor links, due to the way the default slug function works. Consider using a Unicode-aware slug function, as documented here.
Source · Default: automatically set
Some languages, like Arabic or Japanese, need dedicated stemmers for search to work properly. Material for MkDocs relies on lunr-languages to provide this functionality. See the guide detailing how to set up site search for more information.
Source · Default: automatically set
While many languages are read ltr
(left-to-right), Material for MkDocs also supports
rtl
(right-to-left) directionality which is inferred from the selected language, but can
also be set with:
theme:
direction: ltr
Click on a tile to change the directionality:
Source · Difficulty: easy
If you want to customize some (or all) of the translations for your language, you may follow the guide on theme extension and create a new partial in
partials/language
, e.g. en-custom.html
. Next, look up the translation you want to
change in the base
translation and add it to the partial.
Let's say you want to change "Table of contents" to "On this page":
{% macro t(key) %}{{ {
"toc.title": "On this page"
}[key] }}{% endmacro %}
Then, add the following lines to mkdocs.yml
:
theme:
language: en-custom
When installing Material for MkDocs, you immediately get access to over 7.000 icons ready to be used for customization of specific parts of the theme and/or when writing your documentation in Markdown. Not enough? You can also add additional icons with minimal effort.
Source · Default: material/library
There're two ways to specify a logo: it must be a valid path to any icon bundled with the
theme, or to a user-provided image located in the docs
folder. Both can be set via
mkdocs.yml
:
theme:
icon:
logo: material/library
theme:
logo: assets/logo.png
Source · Default: assets/images/favicon.png
The favicon can be changed to a path pointing to a user-provided image, which must be located in the
docs
folder. It can be set via mkdocs.yml
:
theme:
favicon: images/favicon.png
The Emoji extension, which
is part of Python Markdown Extensions, adds
the ability to integrate icons in the *.svg
file format, which are inlined when
building your site:
markdown_extensions:
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
The following icon sets are bundled with Material for MkDocs:
If you want to add additional icons, read on.
Source · Difficulty: moderate
In order to add additional icons, extend the theme, and
create a folder named .icons
in the custom_dir
you want to
use for overrides. Next, add your *.svg
icons into a subfolder of the .icons
folder.
Let's say you downloaded and unpacked the Bootstrap icon set,
and want to add it to your project documentation. The structure of your project should look like this:
.
├─ docs/
│ └─ index.md
├─ overrides/
│ └─ .icons/
│ └─ bootstrap/
│ └─ *.svg
└─ mkdocs.yml
Then, add the following lines to mkdocs.yml
:
markdown_extensions:
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
options:
custom_icons:
- overrides/.icons
You should now be able to use the Bootstrap icons.
Material for MkDocs provides an excellent, client-side search implementation, omitting the need for the integration of third-party services, which might violate data privacy regulations. Moreover, with some effort, search can be made available offline.
Source · Plugin · Insiders – improved user experience
The built-in search plugin integrates
seamlessly with Material for MkDocs, adding multilingual client-side search with lunr and lunr-languages. It's enabled by default, but must
be re-added to mkdocs.yml
when other plugins are used:
plugins:
- search
The following options are supported:
lang
Default: automatically set – This option allows to include the language-specific stemmers provided by lunr-languages. Note that Material for MkDocs will set this automatically based on the site language, but it may be overridden, e.g. to support multiple languages:
plugins:
- search:
lang: ru
plugins:
- search:
lang:
- en
- ru
The following languages are supported:
ar
– Arabicda
– Danishdu
– Dutchen
– Englishfi
– Finnishfr
– Frenchde
– Germanhu
– Hungarianit
– Italianja
– Japaneseno
– Norwegianpt
– Portuguesero
– Romanianru
– Russianes
– Spanishsv
– Swedishth
– Thaitr
– Turkishvi
– VietnameseMaterial for MkDocs also tries to support languages that are not part of this list by choosing the stemmer yielding the best result automatically.
Only specify the languages you really need
Be aware that including support for other languages increases the general JavaScript payload by around
20kb (before gzip
) and by another 15-30kb per language.
separator
Default: automatically set – The separator for indexing and query tokenization
can be customized, making it possible to index parts of words separated by other characters than
whitespace and -
, e.g. by including .
:
plugins:
- search:
separator: '[\s\-\.]+'
prebuild_index
Default: false
· Experimental – MkDocs can generate a prebuilt index of all pages
during build time, which provides performance improvements at the cost of more bandwidth, as it reduces
the build time of the search index:
plugins:
- search:
prebuild_index: true
This may be beneficial for large documentation projects served with appropriate headers, i.e.
Content-Encoding: gzip
, but benchmarking before deployment is recommended.
Material for MkDocs doesn't provide official support for the other options of this plugin, so they may be supported but can also yield weird results. Use them at your own risk.
Source · Feature flag · Experimental · Insiders only
When search highlighting is activated and a user clicks on a search result, Material for MkDocs will
highlight all occurrences after following the link. It can be enabled via mkdocs.yml
with:
theme:
features:
- search.highlight
Searching for "code blocks"
yields:
Give this feature a try on the official documentation built with Material for MkDocs Insiders!
Source · Plugin · Experimental
If you distribute your documentation as *.html
files, the built-in search will not work
out-of-the-box due to the restrictions modern browsers impose for security reasons. This can be mitigated with
the localsearch plugin in combination with @squidfunk's iframe-worker polyfill.
For setup instructions, refer to the official documentation.
The search implementation of Material for MkDocs is probably its most sophisticated feature, as it tries to balance a great typeahead experience, good performance, accessibility, and a result list that is easy to scan. This is where Material for MkDocs deviates from other themes.
The following section explains how search can be customized to tailor it to your needs.
Source · Difficulty: easy
When a user enters a query into the search box, the query is pre-processed before it is submitted to the search index. Material for MkDocs will apply the following transformations, which can be customized by extending the theme:
/**
* Default transformation function
*
* 1. Search for terms in quotation marks and prepend a `+` modifier to denote
* that the resulting document must contain all terms, converting the query
* to an `AND` query (as opposed to the default `OR` behavior). While users
* may expect terms enclosed in quotation marks to map to span queries, i.e.
* for which order is important, `lunr` doesn't support them, so the best
* we can do is to convert the terms to an `AND` query.
*
* 2. Replace control characters which are not located at the beginning of the
* query or preceded by white space, or are not followed by a non-whitespace
* character or are at the end of the query string. Furthermore, filter
* unmatched quotation marks.
*
* 3. Trim excess whitespace from left and right.
*
* 4. Append a wildcard to the end of every word to make every word a prefix
* query in order to provide a good typeahead experience, by adding an
* asterisk (wildcard) in between terms, which can be denoted by whitespace,
* any non-control character, or a word boundary.
*
* @param query - Query value
*
* @return Transformed query value
*/
function defaultTransform(query: string): string {
return query
.split(/"([^"]+)"/g) /* => 1 */
.map((terms, i) => i & 1
? terms.replace(/^\b|^(?![^\x00-\x7F]|$)|\s+/g, " +")
: terms
)
.join("")
.replace(/"|(?:^|\s+)[*+\-:^~]+(?=\s+|$)/g, "") /* => 2 */
.trim() /* => 3 */
.replace(/\s+|(?![^\x00-\x7F]|^)$|\b$/g, "* ") /* => 4 */
}
If you want to switch to the default behavior of the mkdocs
or readthedocs
template, both of which don't transform the query prior to submission, or customize the transform
function, you can do this by overriding the config
block:
{% block config %}
<script>
var search = {
transform: function(query) {
return query
}
}
</script>
{% endblock %}
The transform
function will receive the query string as entered by the user and must return the
processed query string to be submitted to the search index.
Source · Difficulty: challenging
Material for MkDocs implements search as part of a web worker. If
you want to switch the web worker with your own implementation, e.g. to submit search to an external service,
you can add a custom JavaScript file to the docs
directory and override the config
block:
{% block config %}
<script>
var search = {
worker: "<url>"
}
</script>
{% endblock %}
Communication with the search worker is implemented using a standardized message format using
discriminated unions, i.e. through the type
property of the message. See the following
interface definitions to learn about the message formats:
The sequence and direction of messages is rather intuitive:
SearchSetupMessage
SearchReadyMessage
SearchQueryMessage
SearchResultMessage
As with any other service offered on the web, understanding how your project documentation is actually used can be an essential success factor. While Material for MkDocs natively integrates with Google Analytics, other analytics services can be used, too.
Source · Default: none
After heading over to your Google Analytics account to
create a new property in order to obtain a
unique tracking id of the form UA-XXXXXXXX-X
, add it to mkdocs.yml
:
google_analytics:
- UA-XXXXXXXX-X
- auto
Besides basic page views, site search can also be tracked to understand better how people use your documentation and what they expect to find. To enable search tracking:
q
.Source · Difficulty: easy
In order to integrate another analytics service provider offering an asynchronous JavaScript-based tracking
solution, you can extend the theme and override the analytics
block:
{% block analytics %}
<!-- Add custom analytics integration here -->
{% endblock %}
If you're using instant loading, you may use the
location$
observable, which will emit the current URL
to listen for navigation
events and register a page view event with:
app.location$.subscribe(function(url) {
/* Add custom page event tracking here */
})
Note that this must be integrated with additional
JavaScript, and cannot be included as part of the analytics
block, as it is included in the
head
of the document.
Material for MkDocs' header can be customized to show an announcement bar that disappears upon scrolling, and provides some options for further configuration. It also includes the search bar and a place to display your project's git repository, as explained in those dedicated guides.
Source · Feature flag · Experimental · Insiders only
When auto-hiding is activated, the header is automatically hidden when the user scrolls past a
certain threshold, leaving more space for content. It can be enabled via mkdocs.yml
with:
theme:
features:
- header.hide
Give this feature a try on the official documentation built with Material for MkDocs Insiders!
Material for MkDocs includes an announcement bar, which is the perfect place to display project news or other
important information to the user. When the user scrolls past the header, the bar will automatically
disappear. In order to add an announcement bar, extend the
theme and override the announce
block,
which is empty by default:
{% block announce %}
<!-- Add your announcement here, including arbitrary HTML -->
{% endblock %}
The footer of your project documentation is a great place to add links to websites or platforms you or your
company are using as additional marketing channels, e.g. , or , which can be configured via mkdocs.yml
.
Source · Default: none
All social links are rendered next to the copyright information as part of the footer of your
project documentation. Add a list of social links in mkdocs.yml
with:
extra:
social:
- icon: fontawesome/brands/twitter
link: https://twitter.com/squidfunk
For each entry, the following fields are available:
icon
Default: none · Required – This field must point to a valid icon path referencing any icon bundled with the theme, or the build will not succeed. Some popular choices:
fontawesome/brands/behance
fontawesome/brands/docker
fontawesome/brands/github
fontawesome/brands/instagram
fontawesome/brands/linkedin
fontawesome/brands/medium
fontawesome/brands/pied-piper-alt
fontawesome/brands/product-hunt
fontawesome/brands/slack
fontawesome/brands/twitter
link
Default: none · Required – This field must contain a valid relative or absolute URL including the URI
scheme. All URI schemes are supported, including mailto
and bitcoin
:
extra:
social:
- icon: fontawesome/brands/twitter
link: https://twitter.com/squidfunk
extra:
social:
- icon: fontawesome/solid/paper-plane
link: mailto:<email-address>
name
Default: domain name from link
, if available – This field
is used as the link's title
attribute and can be set to a discernable name to improve
accessibility:
extra:
social:
- icon: fontawesome/brands/twitter
link: https://twitter.com/squidfunk
name: squidfunk on Twitter
Source · Difficulty: moderate
The social links feature uses the standard icon integration of Material for MkDocs. If you want to use custom icons, follow the guide explaining how to add additional icons.
If your documentation is related to source code, Material for MkDocs provides the ability to display information to the project's repository as part of the static site, including statistics like stars and forks. Furthermore, individual documents can be linked to specific source files.
In order to display a link to the repository of your project as part of your documentation, set repo_url
in
mkdocs.yml
to the public URL of your repository, e.g.:
repo_url: https://github.com/squidfunk/mkdocs-material
The link to the repository will be rendered next to the search bar on big screens and as part of the main navigation drawer on smaller screen sizes. Additionally, for GitHub and GitLab, the number of stars and forks is automatically requested and rendered for public repositories.
Source · Default: automatically set to GitHub
, GitLab
or
Bitbucket
MkDocs will infer the source provider by examining the URL and try to set the repository name
automatically. If you wish to customize the name, set repo_name
in
mkdocs.yml
:
repo_name: squidfunk/mkdocs-material
Source · Default: fontawesome/brands/git-alt
While the default repository icon is a generic git icon, it can be set to any icon bundled with the
theme by referencing a valid icon path in mkdocs.yml
:
theme:
icon:
repo: fontawesome/brands/git-alt
Some popular choices:
fontawesome/brands/git
fontawesome/brands/git-alt
fontawesome/brands/git-square
fontawesome/brands/github
fontawesome/brands/github-alt
fontawesome/brands/github-square
fontawesome/brands/gitlab
fontawesome/brands/gitkraken
fontawesome/brands/bitbucket
fontawesome/solid/trash
Source · Default: automatically set
If the repository URL points to a GitHub, GitLab or Bitbucket repository, an
edit button is displayed at the top of each document. This behavior can be changed by setting edit_uri
in
mkdocs.yml
:
edit_uri: edit/master/docs/
edit_uri: ""
The git-revision-date plugin adds
support for displaying the date a document was last updated at the bottom of each page. It can be
installed with pip
:
pip install mkdocs-git-revision-date-plugin
Then, add the following to mkdocs.yml
:
plugins:
- git-revision-date
The following options are supported:
enabled_if_env
Default: none – This option defines whether the date is actually extracted from git, which makes it possible to disable extraction for cases when the repository is not available:
plugins:
- git-revision-date:
enabled_if_env: CI
Material for MkDocs doesn't provide official support for the other options of this plugin, so they may be supported but can also yield weird results. Use them at your own risk.
Similarly, the git-revision-date-localized
plugin adds support for adding a localized last updated date at the bottom of each page. It can be
installed with pip
:
pip install mkdocs-git-revision-date-localized-plugin
Then, add the following to mkdocs.yml
:
plugins:
- git-revision-date-localized
The following options are supported:
type
Default: date
– This option allows to change the format of the date to be
displayed. Valid values are date
, datetime
, iso_date
,
iso_datetime
and timeago
:
plugins:
- git-revision-date-localized:
type: date
fallback_to_build_date
Default: false
– This option specifies whether the time when
mkdocs build
was executed should be used as a fallback when the git repository is not
available:
plugins:
- git-revision-date-localized:
fallback_to_build_date: true
Material for MkDocs doesn't provide official support for the other options of this plugin, so they may be supported but can also yield weird results. Use them at your own risk.
Material for MkDocs is natively integrated with Disqus, a comment system that provides a wide range of features like social integrations, user profiles, as well as spam and moderation tools. Of course, other comment systems can be integrated, too.
Source · Default: none
First, ensure you've set site_url
in
mkdocs.yml
. Then, to integrate Material for MkDocs with Disqus,
create an account and a site giving you a shortname, and add it to
mkdocs.yml
:
extra:
disqus: <shortname>
This will insert a comment system on every page, except the index page.
The Metadata extension,
which is part of the standard Markdown library, adds the ability to add front matter to a document and can be enabled via
mkdocs.yml
:
markdown_extensions:
- meta
Front matter is written as a series of key-value pairs at the beginning of the Markdown document, delimited by a blank line which ends the YAML context.
Source · Difficulty: easy
If the Metadata extension is enabled, you can disable or enable Disqus for specific pages by adding the following to the front matter of a page:
---
disqus: <shortname>
---
---
disqus: ""
---
Source · Difficulty: easy
In order to integrate another JavaScript-based comment system provider, you can extend the theme and override the disqus
block:
{% block disqus %}
<!-- Add custom comment system integration here -->
{% endblock %}
Admonitions, also known as call-outs, are an excellent choice for including side content without significantly interrupting the document flow. Material for MkDocs provides several different types of admonitions and allows for the inclusion and nesting of arbitrary content.
The Admonition extension, which is
part of the standard Markdown library, is integrated with Material for MkDocs and can be enabled via
mkdocs.yml
:
markdown_extensions:
- admonition
The Details extension,
which is part of Python Markdown Extensions,
adds the ability to make admonitions collapsible. It can be enabled via
mkdocs.yml
:
markdown_extensions:
- pymdownx.details
The SuperFences extension, which is also part of Python Markdown Extensions, allows for the nesting of code and content blocks inside admonitions, and is therefore strongly recommended:
markdown_extensions:
- pymdownx.superfences
Admonitions follow a simple syntax: a block must start with !!!
, followed by a single keyword
which is used as the type qualifier of the block. The
content of the block then follows on the next line, indented by four spaces.
Example:
!!! note
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
massa, nec semper lorem quam in massa.
Result:
Note
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
By default, the title will equal the type qualifier in titlecase. However, it can be changed by adding a quoted string containing valid Markdown (including links, formatting, ...) after the type qualifier.
Example:
!!! note "Phasellus posuere in sem ut cursus"
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
massa, nec semper lorem quam in massa.
Result:
Phasellus posuere in sem ut cursus
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
Similar to changing the title, the icon and title can be omitted entirely by adding an empty string directly after the type qualifier. Note that this will not work for collapsible blocks.
Example:
!!! note ""
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
massa, nec semper lorem quam in massa.
Result:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
Admonitions can contain all kinds of text content, including headlines, lists, paragraphs and other blocks. While the parser from the standard Markdown library doesn't account for nested blocks, the SuperFences extension adds the ability to nest arbitrary content inside admonitions.
Example:
!!! note
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
massa, nec semper lorem quam in massa.
``` python
def bubble_sort(items):
for i in range(len(items)):
for j in range(len(items) - 1 - i):
if items[j] > items[j + 1]:
items[j], items[j + 1] = items[j + 1], items[j]
```
Nunc eu odio eleifend, blandit leo a, volutpat sapien. Phasellus posuere in
sem ut cursus. Nullam sit amet tincidunt ipsum, sit amet elementum turpis.
Etiam ipsum quam, mattis in purus vitae, lacinia fermentum enim.
Result:
Note
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
def bubble_sort(items):
for i in range(len(items)):
for j in range(len(items) - 1 - i):
if items[j] > items[j + 1]:
items[j], items[j + 1] = items[j + 1], items[j]
Nunc eu odio eleifend, blandit leo a, volutpat sapien. Phasellus posuere in sem ut cursus. Nullam sit amet tincidunt ipsum, sit amet elementum turpis. Etiam ipsum quam, mattis in purus vitae, lacinia fermentum enim.
The Details extension
adds support for rendering collapsible admonition blocks. This is useful for FAQs or content that is of
secondary nature. A details block follows the syntax and semantics of admonition blocks, but must start with
???
.
Example:
??? note
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
massa, nec semper lorem quam in massa.
Result:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
Adding a +
after ???
will render the block as open on page load:
Example:
???+ note
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
massa, nec semper lorem quam in massa.
Result:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
Following is a list of type qualifiers provided by Material for MkDocs, whereas the default type, and thus
fallback for unknown type qualifiers, is note
:
note
, seealso
Note
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
abstract
, summary
, tldr
Abstract
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
info
, todo
Info
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
tip
, hint
, important
Tip
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
success
, check
, done
Success
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
question
, help
, faq
Question
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
warning
, caution
, attention
Warning
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
failure
, fail
, missing
Failure
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
danger
, error
Danger
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
bug
Bug
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
example
Example
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
quote
, cite
Quote
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
If you want to add a custom admonition type, all you need is a color and an svg
icon. Copy the
icon's svg
code from the .icons
folder and add the following CSS to an additional
stylesheet:
:root {
--md-admonition-icon--pied-piper: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M244 246c-3.2-2-6.3-2.9-10.1-2.9-6.6 0-12.6 3.2-19.3 3.7l1.7 4.9zm135.9 197.9c-19 0-64.1 9.5-79.9 19.8l6.9 45.1c35.7 6.1 70.1 3.6 106-9.8-4.8-10-23.5-55.1-33-55.1zM340.8 177c6.6 2.8 11.5 9.2 22.7 22.1 2-1.4 7.5-5.2 7.5-8.6 0-4.9-11.8-13.2-13.2-23 11.2-5.7 25.2-6 37.6-8.9 68.1-16.4 116.3-52.9 146.8-116.7C548.3 29.3 554 16.1 554.6 2l-2 2.6c-28.4 50-33 63.2-81.3 100-31.9 24.4-69.2 40.2-106.6 54.6l-6.3-.3v-21.8c-19.6 1.6-19.7-14.6-31.6-23-18.7 20.6-31.6 40.8-58.9 51.1-12.7 4.8-19.6 10-25.9 21.8 34.9-16.4 91.2-13.5 98.8-10zM555.5 0l-.6 1.1-.3.9.6-.6zm-59.2 382.1c-33.9-56.9-75.3-118.4-150-115.5l-.3-6c-1.1-13.5 32.8 3.2 35.1-31l-14.4 7.2c-19.8-45.7-8.6-54.3-65.5-54.3-14.7 0-26.7 1.7-41.4 4.6 2.9 18.6 2.2 36.7-10.9 50.3l19.5 5.5c-1.7 3.2-2.9 6.3-2.9 9.8 0 21 42.8 2.9 42.8 33.6 0 18.4-36.8 60.1-54.9 60.1-8 0-53.7-50-53.4-60.1l.3-4.6 52.3-11.5c13-2.6 12.3-22.7-2.9-22.7-3.7 0-43.1 9.2-49.4 10.6-2-5.2-7.5-14.1-13.8-14.1-3.2 0-6.3 3.2-9.5 4-9.2 2.6-31 2.9-21.5 20.1L15.9 298.5c-5.5 1.1-8.9 6.3-8.9 11.8 0 6 5.5 10.9 11.5 10.9 8 0 131.3-28.4 147.4-32.2 2.6 3.2 4.6 6.3 7.8 8.6 20.1 14.4 59.8 85.9 76.4 85.9 24.1 0 58-22.4 71.3-41.9 3.2-4.3 6.9-7.5 12.4-6.9.6 13.8-31.6 34.2-33 43.7-1.4 10.2-1 35.2-.3 41.1 26.7 8.1 52-3.6 77.9-2.9 4.3-21 10.6-41.9 9.8-63.5l-.3-9.5c-1.4-34.2-10.9-38.5-34.8-58.6-1.1-1.1-2.6-2.6-3.7-4 2.2-1.4 1.1-1 4.6-1.7 88.5 0 56.3 183.6 111.5 229.9 33.1-15 72.5-27.9 103.5-47.2-29-25.6-52.6-45.7-72.7-79.9zm-196.2 46.1v27.2l11.8-3.4-2.9-23.8zm-68.7-150.4l24.1 61.2 21-13.8-31.3-50.9zm84.4 154.9l2 12.4c9-1.5 58.4-6.6 58.4-14.1 0-1.4-.6-3.2-.9-4.6-26.8 0-36.9 3.8-59.5 6.3z"/></svg>')
}
.md-typeset .admonition.pied-piper,
.md-typeset details.pied-piper {
border-color: rgb(43, 155, 70);
}
.md-typeset .pied-piper > .admonition-title,
.md-typeset .pied-piper > summary {
background-color: rgba(43, 155, 70, 0.1);
}
.md-typeset .pied-piper > .admonition-title::before,
.md-typeset .pied-piper > summary::before {
background-color: rgb(43, 155, 70);
-webkit-mask-image: var(--md-admonition-icon--pied-piper);
mask-image: var(--md-admonition-icon--pied-piper);
}
You should now be able to create an admonition of the pied-piper
type. Note that you can also
use this technique to override existing admonition icons or colors. You can even add
animations.
Example:
!!! pied-piper "Pied Piper"
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
massa, nec semper lorem quam in massa.
Result:
Pied Piper
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
Material for MkDocs provides dedicated styles for primary and secondary buttons that can be added to any link,
label
or button
element. This is especially useful for documents or landing pages with
dedicated call-to-actions.
The Attribute List extension, which is
part of the standard Markdown library, allows to add HTML attributes and CSS classes to Markdown
elements, and can be enabled via mkdocs.yml
markdown_extensions:
- attr_list
When the Attribute List extension is enabled, any clickable
element can be converted into a button by adding the .md-button
CSS class, which will receive the
selected primary color.
Example:
[Subscribe to our mailing list](#){: .md-button }
Result:
If you want to display a filled, primary button (like on the landing page of Material for
MkDocs), add both the .md-button
and .md-button--primary
CSS classes.
Example:
[Subscribe to our mailing list](#){: .md-button .md-button--primary }
Result:
Of course, icons can be added to both types of buttons by using the regular icon syntax and referencing a valid path to any icon bundled with the theme.
Example:
[Submit :fontawesome-solid-paper-plane:](#){: .md-button .md-button--primary }
Result:
Code blocks and examples are an essential part of technical project documentation. Material for MkDocs provides different ways to set up syntax highlighting for code blocks, either during build time using Pygments or during runtime using a JavaScript syntax highlighter.
Source · Extension · Supersedes: CodeHilite
The Highlight extension, which is part of Python Markdown Extensions, integrates with Material for MkDocs and provides several options for configuring syntax highlighting of code blocks:
use_pygments
Default: true
– This option allows to control whether highlighting should be
carried out during build time by Pygments or runtime with a JavaScript
highlighter. Remember to add the necessary additional
stylesheets and JavaScript if you want to use
the latter:
markdown_extensions:
- pymdownx.highlight:
use_pygments: true
markdown_extensions:
- pymdownx.highlight:
use_pygments: false
Highlight.js can be integrated by creating an additional JavaScript file initializing the
highlighter and including the respective stylesheet and JavaScript from a CDN serving Highlight.js in
mkdocs.yml
:
hljs.initHighlighting()
extra_javascript:
- https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js
- javascripts/config.js
extra_css:
- https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/default.min.css
Note that Highlight.js has no affiliation with the Highlight extension.
linenums
Default: false
– This option will add line numbers to all code
blocks. If you wish to add line numbers to some, but not all code blocks, consult the section on
adding line numbers later in this document,
which also contains some tips on working with line numbers:
markdown_extensions:
- pymdownx.highlight:
linenums: true
linenums_style
Default: table
– The Highlight extension provides three ways to add line
numbers, all of which are supported by Material for MkDocs. While table
wraps a code block in
a table, inline
and pymdownx.inline
render line numbers as part of the line
itself:
markdown_extensions:
- pymdownx.highlight:
linenums_style: pymdownx.inline
Note that inline
will put line numbers next to the actual code, which means that they will
be included when selecting text with the cursor or copying a code block to the clipboard. Thus, the usage
of table
or pymdownx.inline
is recommended.
Material for MkDocs doesn't provide official support for the other options of this extension, so they may be supported but can also yield weird results. Use them at your own risk.
The InlineHilite
extension, which is part of Python Markdown
Extensions also integrates with Material for MkDocs and adds support for syntax highlighting of
inline code blocks. It's built on top of the Highlight extension and
can be enabled via mkdocs.yml
:
markdown_extensions:
- pymdownx.inlinehilite
See the section on inline code blocks for usage information.
The Keys extension, which is
part of Python Markdown Extensions, allows
for inserting keyboard keys, e.g. Ctrl+Alt+Del , and can be enabled via mkdocs.yml
:
markdown_extensions:
- pymdownx.keys
The SuperFences extension, which is also part of Python Markdown Extensions, allows for the nesting of code blocks inside other blocks, and is therefore strongly recommended:
markdown_extensions:
- pymdownx.superfences
The Snippets extension,
which is also part of Python Markdown
Extensions, allows to insert content from other files or other, regular content, and
can be enabled via mkdocs.yml
:
markdown_extensions:
- pymdownx.snippets
This section discusses how to use different syntax highlighting features with Pygments – the default highlighter – so they don't apply when using a JavaScript syntax highlighter.
Code blocks must be enclosed with two separate lines containing three backticks. To add code highlighting to those blocks, add the language short name directly after the opening block. See the list of available lexers to find the short name for a given language.
Example:
``` python
import tensorflow as tf
```
Result:
import tensorflow as tf
Line numbers can be added to a code block by using the linenums="<start>"
option directly
after the short name, whereas <start>
represents the starting line number. A code block can
start from a line number other than 1
, which allows splitting large code blocks for readability.
Example:
``` python linenums="1"
def bubble_sort(items):
for i in range(len(items)):
for j in range(len(items) - 1 - i):
if items[j] > items[j + 1]:
items[j], items[j + 1] = items[j + 1], items[j]
```
Result:
1 2 3 4 5 |
|
Specific lines can be highlighted by passing the line numbers to the hl_lines
argument placed
right after the language short name. Note that line counts start at 1
, regardless of the starting
line number specified as part of linenums
.
Example:
``` python hl_lines="2 3"
def bubble_sort(items):
for i in range(len(items)):
for j in range(len(items) - 1 - i):
if items[j] > items[j + 1]:
items[j], items[j + 1] = items[j + 1], items[j]
```
Result:
def bubble_sort(items):
for i in range(len(items)):
for j in range(len(items) - 1 - i):
if items[j] > items[j + 1]:
items[j], items[j + 1] = items[j + 1], items[j]
When InlineHilite is enabled, inline code blocks can be
highlighted by prefixing them with a shebang-like sequence, i.e. #!
, directly followed by the language short name.
Example:
The `#!python range()` function is used to generate a sequence of numbers.
Result:
The range()
function is used to
generate a sequence of numbers.
When Keys is enabled, keyboard keys can be rendered with a simple syntax. Consult the Python Markdown Extensions documentation to learn about all available key codes.
Example:
++ctrl+alt+del++
Result:
Ctrl+Alt+Del
Also known as transcludes or file transclusion in MultiMarkdown.
When Snippets is enabled, content from other files can be embedded, which is especially useful to reference and embed the contents of source files directly into your project documentation.
Example:
```
--8<-- ".browserslistrc"
```
Result:
last 4 years
Note that Snippets is not limited to code blocks, but can be used anywhere from a document to move repeating content to separate files, which is also explained in the official documentation.
Source · Difficulty: easy
If Pygments is used, Material for MkDocs provides the styles for code blocks, which are built with a custom and well-balanced palette that works equally well for both color schemes:
--md-code-hl-number-color
--md-code-hl-special-color
--md-code-hl-function-color
--md-code-hl-constant-color
--md-code-hl-keyword-color
--md-code-hl-string-color
--md-code-hl-name-color
--md-code-hl-operator-color
--md-code-hl-punctuation-color
--md-code-hl-comment-color
--md-code-hl-generic-color
--md-code-hl-variable-color
Code block foreground, background and line highlight colors are defined via:
--md-code-fg-color
--md-code-bg-color
--md-code-hl-color
Let's say you want to change the color of "strings"
.
While there are several types of string tokens,
Material for MkDocs assigns a single color to most of them.
Create an additional stylesheet, and add:
:root > * {
--md-code-hl-string-color: #0FF1CE;
}
If you want to tweak a specific type of string, i.e. `backticks`
, you can lookup the specific class name in the
syntax
theme definition, and override it as part of your additional stylesheet:
.highlight .sb {
color: #0FF1CE;
}
Sometimes, it's desirable to group alternative content under different tabs, e.g. when describing how to access an API from different languages or environments. Material for MkDocs allows for beautiful and functional tabs, grouping code blocks and other content.
The Tabbed extension,
which is part of Python Markdown Extensions,
integrates with Material for MkDocs and can be enabled via mkdocs.yml
:
markdown_extensions:
- pymdownx.tabbed
The SuperFences extension, which is also part of Python Markdown Extensions, allows for the nesting of code and content blocks inside tabs, and is therefore strongly recommended:
markdown_extensions:
- pymdownx.superfences
Code blocks are one of the primary targets to be grouped, and can be considered a special case of content tabs, as tabs with a single code block are always rendered without horizontal spacing.
Example:
=== "C"
``` c
#include <stdio.h>
int main(void) {
printf("Hello world!\n");
return 0;
}
```
=== "C++"
``` c++
#include <iostream>
int main(void) {
std::cout << "Hello world!" << std::endl;
return 0;
}
```
Result:
#include <stdio.h>
int main(void) {
printf("Hello world!\n");
return 0;
}
#include <iostream>
int main(void) {
std::cout << "Hello world!" << std::endl;
return 0;
}
When a content tab contains more than one code block, it is rendered with horizontal spacing. Vertical spacing is never added, but can be achieved by nesting tabs in other blocks.
Example:
=== "Unordered list"
* Sed sagittis eleifend rutrum
* Donec vitae suscipit est
* Nulla tempor lobortis orci
=== "Ordered list"
1. Sed sagittis eleifend rutrum
2. Donec vitae suscipit est
3. Nulla tempor lobortis orci
Result:
When SuperFences is enabled, content tabs can contain arbitrary nested content, including further content tabs, and can be nested in other blocks like admonitions, details or blockquotes:
Example:
!!! example
=== "Unordered List"
_Example_:
``` markdown
* Sed sagittis eleifend rutrum
* Donec vitae suscipit est
* Nulla tempor lobortis orci
```
_Result_:
* Sed sagittis eleifend rutrum
* Donec vitae suscipit est
* Nulla tempor lobortis orci
=== "Ordered List"
_Example_:
``` markdown
1. Sed sagittis eleifend rutrum
2. Donec vitae suscipit est
3. Nulla tempor lobortis orci
```
_Result_:
1. Sed sagittis eleifend rutrum
2. Donec vitae suscipit est
3. Nulla tempor lobortis orci
Result:
Example
Example:
* Sed sagittis eleifend rutrum
* Donec vitae suscipit est
* Nulla tempor lobortis orci
Result:
Example:
1. Sed sagittis eleifend rutrum
2. Donec vitae suscipit est
3. Nulla tempor lobortis orci
Result:
Material for MkDocs defines default styles for data tables – an excellent way of rendering tabular data in project documentation. Furthermore, customizations like sortable tables can be achieved with a third-party library and some additional JavaScript.
None.
Data tables can be used at any position in your project documentation and can contain arbitrary Markdown, including inline code blocks, as well as icons and emojis.
Example:
| Method | Description |
| ----------- | ------------------------------------ |
| `GET` | :material-check: Fetch resource |
| `PUT` | :material-check-all: Update resource |
| `DELETE` | :material-close: Delete resource |
Result:
Method | Description |
---|---|
GET |
Fetch resource |
PUT |
Update resource |
DELETE |
Delete resource |
If you want to align a specific column to the left
, center
or right
,
you can use the regular Markdown syntax
placing :
characters at the beginning and/or end of the divider.
Example:
| Method | Description |
| :---------- | :----------------------------------- |
| `GET` | :material-check: Fetch resource |
| `PUT` | :material-check-all: Update resource |
| `DELETE` | :material-close: Delete resource |
Result:
Method | Description |
---|---|
GET |
Fetch resource |
PUT |
Update resource |
DELETE |
Delete resource |
Example:
| Method | Description |
| :---------: | :----------------------------------: |
| `GET` | :material-check: Fetch resource |
| `PUT` | :material-check-all: Update resource |
| `DELETE` | :material-close: Delete resource |
Result:
Method | Description |
---|---|
GET |
Fetch resource |
PUT |
Update resource |
DELETE |
Delete resource |
Example:
| Method | Description |
| ----------: | -----------------------------------: |
| `GET` | :material-check: Fetch resource |
| `PUT` | :material-check-all: Update resource |
| `DELETE` | :material-close: Delete resource |
Result:
Method | Description |
---|---|
GET |
Fetch resource |
PUT |
Update resource |
DELETE |
Delete resource |
If you want to make data tables sortable, you can add tablesort, which is natively integrated with Material for MkDocs and will also work with instant loading via additional JavaScript:
app.document$.subscribe(function() {
var tables = document.querySelectorAll("article table")
tables.forEach(function(table) {
new Tablesort(table)
})
})
extra_javascript:
- https://cdnjs.cloudflare.com/ajax/libs/tablesort/5.2.1/tablesort.min.js
- javascripts/tables.js
Note that tablesort provides alternative comparison implementations like numbers, dates, filesizes and month names. See the official documentation for more information.
Example:
| Method | Description |
| ----------- | ------------------------------------ |
| `GET` | :material-check: Fetch resource |
| `PUT` | :material-check-all: Update resource |
| `DELETE` | :material-close: Delete resource |
Result:
Method | Description |
---|---|
GET |
Fetch resource |
PUT |
Update resource |
DELETE |
Delete resource |
Footnotes are a great way to add references to supplemental or additional information for a specific section of a document without interrupting the document flow. Material for MkDocs provides the ability to insert inline footnotes and render them at the bottom of the page.
The Footnotes extension, which is part
of the standard Markdown library, adds the ability to add inline footnotes to a document and can be enabled
via mkdocs.yml
:
markdown_extensions:
- footnotes
A footnote reference must be enclosed in square brackets and must start with a caret ^
, directly
followed by an arbitrary identifier, which is similar to the standard Markdown link syntax.
Example:
Lorem ipsum[^1] dolor sit amet, consectetur adipiscing elit.[^2]
Result:
Lorem ipsum1 dolor sit amet, consectetur adipiscing elit.2
The footnote content must be declared with the same identifier as the reference. It can be inserted at an arbitrary position in the document and is always rendered at the bottom of the page. Furthermore, a backlink to the footnote reference is automatically added.
Short statements can be written on the same line.
Example:
[^1]: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Result:
Jump to footnote at the bottom of the page
Paragraphs can be written on the next line and must be indented by four spaces.
Example:
[^2]:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
massa, nec semper lorem quam in massa.
Result:
Material for MkDocs provides support for several HTML elements that can be used to highlight sections of a document or apply specific formatting. Additionally, Critic Markup is supported, adding the ability to display suggested changes for a document.
The Critic extension,
which is part of Python Markdown Extensions,
allows for the usage of Critic Markup to highlight
changes in a document, and can be enabled via mkdocs.yml
:
markdown_extensions:
- pymdownx.critic
The following options are supported:
mode
Default: view
– This option defines how the markup should be parsed, i.e.
whether to just view
all suggest changes, or alternatively accept
or
reject
them:
markdown_extensions:
- pymdownx.critic:
mode: view
markdown_extensions:
- pymdownx.critic:
mode: accept
markdown_extensions:
- pymdownx.critic:
mode: reject
The BetterEm extension,
which is part of Python Markdown Extensions,
improves the handling of Markup to emphasize text (e.g. bold and italic), and can be
enabled via mkdocs.yml
:
markdown_extensions:
- pymdownx.betterem:
smart_enable: all
The Caret, Mark and Tilde extensions, which are part of Python Markdown Extensions, allow for the highlighting of text, as well as handling sub- and superscripts:
markdown_extensions:
- pymdownx.caret
- pymdownx.mark
- pymdownx.tilde
The SmartSymbols
extension, which is also part of Python Markdown
Extensions, converts special characters into their corresponding symbols, and can be
enabled via mkdocs.yml
:
markdown_extensions:
- pymdownx.smartsymbols
See the official documentation for a list of supported symbols.
When Critic is enabled, Critic Markup can be used, which adds the ability to highlight suggested changes, as well as add inline comments to a document:
Example:
Text can be {--deleted--} and replacement text {++added++}. This can also be
combined into {~~one~>a single~~} operation. {==Highlighting==} is also
possible {>>and comments can be added inline<<}.
{==
Formatting can also be applied to blocks, by putting the opening and closing
tags on separate lines and adding new lines between the tags and the content.
==}
Result:
Text can be deleted and replacement text added. This can
also be combined into onea single operation. Highlighting is also possible and comments can be added
inline.
Formatting can also be applied to blocks, by putting the opening and closing tags on separate lines and adding new lines between the tags and the content.
When the Caret, Mark & Tilde extensions are
enabled, text can be highlighted with a nicer syntax than using the corresponding mark
,
ins
and del
HTML tags:
Example:
* ==This was marked==
* ^^This was inserted^^
* ~~This was deleted~~
Result:
When the Caret & Tilde extensions are enabled, text
can be sub- and superscripted with a nicer syntax than using the corresponding sub
and
sup
HTML tags:
Example:
* H~2~0
* A^T^A
Result:
One of the best features of Material for MkDocs is the possibility to use more than 7.000
icons and thousands of emojis in your project documentation with practically zero
additional effort. Furthermore, custom icons can be used in mkdocs.yml
, documents and templates.
The Emoji extension, which
is part of Python Markdown Extensions, adds
the ability to integrate emojis and icons in the *.svg
file format, which are
inlined when building your site:
markdown_extensions:
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
The following icon sets are bundled with Material for MkDocs:
You can also add additional icons. When using emojis, it's recommended to consult the official documentation of Python Markdown Extensions to learn about configuration options.
The Attribute List extension, which is
part of the standard Markdown library, allows to add HTML attributes and CSS classes to Markdown
elements, and can be enabled via mkdocs.yml
markdown_extensions:
- attr_list
Emojis can be integrated in Markdown by putting the shortcode of the emoji between two colons. If you're using Twemoji (recommended), you can look up the shortcodes at Emojipedia.
Example:
:smile:
Result:
When Emoji is enabled, icons can be used similar to emojis, by
referencing a valid path to any icon bundled with the theme, which are located in the .icons
directory, and replacing /
with -
:
Example:
* :material-account-circle: – `.icons/material/account-circle.svg`
* :fontawesome-regular-laugh-wink: – `.icons/fontawesome/regular/laugh-wink.svg`
* :octicons-octoface-16: – `.icons/octicons/octoface-16.svg`
Result:
.icons/material/account-circle.svg
.icons/fontawesome/regular/laugh-wink.svg
.icons/octicons/octoface-16.svg
When the Attribute List extension is enabled, custom CSS classes and attributes can be added to icons by suffixing the icon with a special syntax. While HTML and CSS allow to use inline styles, it's always best to add an additional stylesheet and put styles into dedicated CSS classes:
.medium {
color: #00AB6C;
}
.twitter {
color: #1DA1F2;
}
.facebook {
color: #4267B2;
}
Then, simply add the CSS class to the icon.
Example:
* :fontawesome-brands-medium:{: .medium } – Medium
* :fontawesome-brands-twitter:{: .twitter } – Twitter
* :fontawesome-brands-facebook:{: .facebook } – Facebook
Result:
Similar to adding colors, it's just as easy to add CSS animations to icons by using an additional stylesheet, defining a @keyframes
rule and adding the
dedicated CSS class to the icon:
@keyframes heart {
0%, 40%, 80%, 100% {
transform: scale(1);
}
20%, 60% {
transform: scale(1.15);
}
}
.heart {
animation: heart 1000ms infinite;
}
Then, simply add the CSS class to the icon.
Example:
:octicons-heart-fill-24:{: .heart }
Result:
When you're extending the theme with partials or blocks,
you can simply reference any icon that's bundled with the theme
with Jinja's include
function and wrap it with the twemoji
class:
<span class="twemoji">
{% include ".icons/fontawesome/brands/twitter.svg" %}
</span>
This is exactly what Material for MkDocs does in its templates.
While images are first-class citizens of Markdown and part of the core syntax, it can be difficult to work with them. Material for MkDocs makes working with images more comfortable by providing styles for alignment and image captions.
The Attribute List extension, which is
part of the standard Markdown library, allows to add HTML attributes and CSS classes to Markdown
elements, and can be enabled via mkdocs.yml
markdown_extensions:
- attr_list
When the Attribute List extension is enabled, images can be
aligned by adding the respective alignment directions via the align
attribute, i.e.
align=left
or align=right
Example:
{: align=left }
Result:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
Example:
{: align=right }
Result:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
If there's insufficient space to render the text next to the image, the image will stretch to the full width of the viewport, e.g. on mobile viewports.
Sadly, the Markdown syntax doesn't provide native support for image captions, but it's always possible to
resort to HTML. Using figure
and figcaption
, captions can be added to images.
Example:
<figure>
<img src="https://dummyimage.com/600x400/eee/aaa" width="300" />
<figcaption>Image caption</figcaption>
</figure>
Result:
Modern browsers provide native support for lazy-loading
images through the loading
attribute, which degrades to eager-loading in browsers without
support. As with image alignment, if the Attribute List extension is enabled, images can be lazy-loaded
by adding loading=lazy
.
Example:
{: loading=lazy }
Result:
Material for MkDocs supports several flavors of lists that cater to different use cases, including unordered lists and ordered lists, which are supported through standard Markdown, as well as definition lists and task lists, which are supported through extensions.
The Definition List extension,
which is part of the standard Markdown library, adds the ability to add definitions lists to a document and
can be enabled via mkdocs.yml
:
markdown_extensions:
- def_list
The Tasklist extension, which is part of Python Markdown Extensions, adds support for lists with styled checkboxes, and provides several options for configuring the style:
custom_checkbox
Default: false
· This option toggles the rendering style of checkboxes,
replacing native checkbox styles with beautiful icons, and is therefore strongly recommended:
markdown_extensions:
- pymdownx.tasklist:
custom_checkbox: true
clickable_checkbox
Default: false
· This option toggles whether checkboxes are clickable. As the
state is not persisted, the use of this option is rather discouraged from a user experience
perspective:
markdown_extensions:
- pymdownx.tasklist:
clickable_checkbox: true
An unordered list can be written by prefixing a line with a -
, *
or +
list marker, all of which can be used interchangeably. Furthermore, all flavors of lists can be nested inside
each other.
Example:
* Nulla et rhoncus turpis. Mauris ultricies elementum leo. Duis efficitur
accumsan nibh eu mattis. Vivamus tempus velit eros, porttitor placerat nibh
lacinia sed. Aenean in finibus diam.
* Duis mollis est eget nibh volutpat, fermentum aliquet dui mollis.
* Nam vulputate tincidunt fringilla.
* Nullam dignissim ultrices urna non auctor.
Result:
Nulla et rhoncus turpis. Mauris ultricies elementum leo. Duis efficitur accumsan nibh eu mattis. Vivamus tempus velit eros, porttitor placerat nibh lacinia sed. Aenean in finibus diam.
An ordered list must start with a number immediately followed by a dot. The numbers do not need to be
consecutive and can be all set to 1.
, as they will be re-numbered when rendered.
Example:
1. Vivamus id mi enim. Integer id turpis sapien. Ut condimentum lobortis
sagittis. Aliquam purus tellus, faucibus eget urna at, iaculis venenatis
nulla. Vivamus a pharetra leo.
1. Vivamus venenatis porttitor tortor sit amet rutrum. Pellentesque aliquet
quam enim, eu volutpat urna rutrum a. Nam vehicula nunc mauris, a
ultricies libero efficitur sed.
2. Morbi eget dapibus felis. Vivamus venenatis porttitor tortor sit amet
rutrum. Pellentesque aliquet quam enim, eu volutpat urna rutrum a.
1. Mauris dictum mi lacus
2. Ut sit amet placerat ante
3. Suspendisse ac eros arcu
Result:
Vivamus id mi enim. Integer id turpis sapien. Ut condimentum lobortis sagittis. Aliquam purus tellus, faucibus eget urna at, iaculis venenatis nulla. Vivamus a pharetra leo.
Vivamus venenatis porttitor tortor sit amet rutrum. Pellentesque aliquet quam enim, eu volutpat urna rutrum a. Nam vehicula nunc mauris, a ultricies libero efficitur sed.
Morbi eget dapibus felis. Vivamus venenatis porttitor tortor sit amet rutrum. Pellentesque aliquet quam enim, eu volutpat urna rutrum a.
Definition lists are a ideal for describing arbitrary key-value pairs, e.g. the parameters of functions or modules, as used within this documentation to describe extension or plugin parameters.
Example:
`Lorem ipsum dolor sit amet`
: Sed sagittis eleifend rutrum. Donec vitae suscipit est. Nullam tempus
tellus non sem sollicitudin, quis rutrum leo facilisis.
`Cras arcu libero`
: Aliquam metus eros, pretium sed nulla venenatis, faucibus auctor ex. Proin
ut eros sed sapien ullamcorper consequat. Nunc ligula ante.
Duis mollis est eget nibh volutpat, fermentum aliquet dui mollis.
Nam vulputate tincidunt fringilla.
Nullam dignissim ultrices urna non auctor.
Result:
Lorem ipsum dolor sit amet
Cras arcu libero
Aliquam metus eros, pretium sed nulla venenatis, faucibus auctor ex. Proin ut eros sed sapien ullamcorper consequat. Nunc ligula ante.
Duis mollis est eget nibh volutpat, fermentum aliquet dui mollis. Nam vulputate tincidunt fringilla. Nullam dignissim ultrices urna non auctor.
When the Tasklist extension is enabled, unordered list items can be
prefixed with [ ]
to render an unchecked or [x]
to render a checked checkbox.
Example:
* [x] Lorem ipsum dolor sit amet, consectetur adipiscing elit
* [ ] Vestibulum convallis sit amet nisi a tincidunt
* [x] In hac habitasse platea dictumst
* [x] In scelerisque nibh non dolor mollis congue sed et metus
* [ ] Praesent sed risus massa
* [ ] Aenean pretium efficitur erat, donec pharetra, ligula non scelerisque
Result:
MathJax is a beautiful and accessible way to display mathematical content in the browser, allows for writing formulas in different notations, including LaTeX, MathML and AsciiMath, and can be easily integrated with Material for MkDocs.
The Arithmatex
extension, which is part of of Python
Markdown Extensions, allows the rendering of block and inline block equations, and can be enabled via
mkdocs.yml
:
markdown_extensions:
- pymdownx.arithmatex:
generic: true
Besides enabling the extension in mkdocs.yml
, a MathJax configuration and the JavaScript runtime
need to be included, which can be done with additional
JavaScript:
window.MathJax = {
tex: {
inlineMath: [["\\(", "\\)"]],
displayMath: [["\\[", "\\]"]],
processEscapes: true,
processEnvironments: true
},
options: {
ignoreHtmlClass: ".*|",
processHtmlClass: "arithmatex"
}
};
extra_javascript:
- javascripts/config.js
- https://polyfill.io/v3/polyfill.min.js?features=es6
- https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
MathJax can be configured in many different ways, for which Material for MkDocs might not provide native support. See the official documentation for more information.
Using MathJax with instant loading
There's no additional effort necessary to integrate MathJax 3 with instant loading – it's expected to work straight away. However, a previous version of this document explained how to integrate Material for MkDocs with MathJax 2, which doesn't exhibit this behavior. It's therefore highly recommended to switch to MathJax 3.
Blocks must be enclosed in $$...$$
or
\[...\]
on
separate lines:
Example:
$$
\operatorname{ker} f=\{g\in G:f(g)=e_{H}\}{\mbox{.}}
$$
Result:
Inline blocks must be enclosed in $...$
or
\(...\)
:
Example:
The homomorphism $f$ is injective if and only if its kernel is only the
singleton set $e_G$, because otherwise $\exists a,b\in G$ with $a\neq b$ such
that $f(a)=f(b)$.
Result:
The homomorphism \(f\) is injective if and only if its kernel is only the singleton set \(e_G\), because otherwise \(\exists a,b\in G\) with \(a\neq b\) such that \(f(a)=f(b)\).
In HTML, meta
tags allow to provide additional metadata for a document, e.g. page titles and
descriptions, additional assets to be loaded, and Open Graph data. While metadata
can always be added via customization, some tags can be
configured.
The Metadata extension,
which is part of the standard Markdown library, adds the ability to add front matter to a document and can be enabled via
mkdocs.yml
:
markdown_extensions:
- meta
Front matter is written as a series of key-value pairs at the beginning of the Markdown document, delimited by a blank line which ends the YAML context.
If the Metadata extension is enabled, the page title can be overridden on a per-document basis with custom front matter:
---
title: Lorem ipsum dolor sit amet
---
This will set the title
tag inside the document head
for the current page to the
provided value. Note that the site title is appended using a dash as a separator, which is the default
behavior.
If the Metadata extension is enabled, the page description can also be overridden on a per-document basis with custom front matter:
---
description: Nullam urna elit, malesuada eget finibus ut, ac tortor.
---
This will set the meta
tag containing the site description inside the document head
for the current page to the provided value.
A web app manifest is a simple
JSON file that specifies how your web application should behave when installed on the user's mobile device or
desktop, which can be set via mkdocs.yml
:
extra:
manifest: manifest.webmanifest
In order to add meta
tags to your document, you can extend the theme and simply override the extrahead
block with the respective
tags, e.g. to set policies for search engines:
{% block extrahead %}
<meta property="robots" content="noindex, nofollow" />
{% endblock %}
Some further examples, including Open Graph and Twitter Cards:
{% block extrahead %}
{% set title = config.site_name %}
{% if page and page.meta and page.meta.title %}
{% set title = title ~ " - " ~ page.meta.title %}
{% elif page and page.title and not page.is_homepage %}
{% set title = title ~ " - " ~ page.title | striptags %}
{% endif %}
<meta property="og:type" content="website" />
<meta property="og:title" content="{{ title }}" />
<meta property="og:description" content="{{ config.site_description }}" />
<meta property="og:url" content="{{ page.canonical_url }}" />
<meta property="og:image" content="<url>" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
{% endblock %}
{% block extrahead %}
{% set title = config.site_name %}
{% if page and page.meta and page.meta.title %}
{% set title = title ~ " - " ~ page.meta.title %}
{% elif page and page.title and not page.is_homepage %}
{% set title = title ~ " - " ~ page.title | striptags %}
{% endif %}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="<username>" />
<meta name="twitter:creator" content="<username>" />
<meta name="twitter:title" content="{{ title }}" />
<meta name="twitter:description" content="{{ config.site_description }}" />
<meta name="twitter:image" content="<url>" />
{% endblock %}
404
for images
when using instant loadingdetails
and content tabs for pointer devices404
on search index when
search is disabledtheme-color
meta tag404.html
to main.html
ins
, del
and mark
outline
for details and code blocks on touch devicesfont-size
and spacings on em
font-size
slate
color scheme to be more customizable and easier on the eyesOR
to AND
de
, fr
, ...)preconnect
hint for
Google Analyticsdeg
values in hsla
colorsscroll-margin-top
*.html
filesname
attribute for social links to set link title
iframe
is not
adjustablefile://
if Worker failssticky
target=_blank
4kb
)app.dialog$.next("Hi!")
in the consolerequirements.txt
tabindex
to
0
for skip to content link.zip
and .tar.gz
h1
contained HTML tagstitle
attributes from links in navigationblack
as a primary colorh1
contained HTML tagsmkdocs-minify-plugin
font-size
is smaller than 16
font-display: swap
to Google Font loading logic4kb
(.7kb
gzipped) per requesthead
using Google Tag Manager.highlighttable
as an
alias for .codehilitetable
id
attributes with
__
to avoid name clashesdetails
on Edge--dev-addr
flag removal from Dockerfile
yarn
with npm 5.6
--dev-addr
flag from Dockerfile
for Windows compatibilitygh-deploy
fails inside Docker
outline
being cut off on Tab focus
of navigation linksoutline
resets for linksexample
(synonym: snippet
) style for Admonitionabstract
for summary
style for Admonitionbabel-preset-es2015
with babel-preset-env
white
as a primary colorbackground-attachment
details
not opening with footnote referencedetails
doesn't open it1220px
and 1234px
mkdocs.yml
info
(synonym: todo
) style for Admonitionquestion
(synonym: help
, faq
) style for Admonitionrepo_url
is not setz-index
order of header, overlay and drawerabbr
tagshtml
tagh1
is presentsetup.py
site_url
h1
is not presentrepo_url
ends
with a /
quote
(synonym: cite
) style for Admonitionh1
is defined as raw HTML0.12rem
_blank
targets on links due to vulnerability: http://bit.ly/1Mk2Rtwpackage.json
404.html
error page for deployment on GitHub Pagesfile://
max-width
on main
tagmkdocs.yml
mkdocs.yml
if
/else
with modifiers where possible)::before
content"None"
mkdocs.yml
with fallbacks/
Upgrade to the latest version with:
pip install --upgrade mkdocs-material
Inspect the currently installed version with:
pip show mkdocs-material
app.dialog$.next("Hi!")
in the consolemkdocs.yml
Following is a list of changes that need to be made to mkdocs.yml
. Note that you only have to
adjust the value if you defined it, so if your configuration does not contain the key, you can skip it.
theme.feature
Optional features like tabs and instant loading are now implemented as flags and
can be enabled by listing them in mkdocs.yml
under theme.features
:
theme:
features:
- tabs
- instant
theme:
feature:
tabs: true
theme.logo.icon
The logo icon configuration was centralized under theme.icon.logo
and can now be set to any of
the icons bundled with the theme:
theme:
icon:
logo: material/cloud
theme:
logo:
icon: cloud
extra.repo_icon
The repo icon configuration was centralized under theme.icon.repo
and can now be set to any of
the icons bundled with the theme:
theme:
icon:
repo: fontawesome/brands/gitlab
extra:
repo_icon: gitlab
extra.search.*
Search is now configured as part of the plugin
options. Note that the search languages must now be listed as an array of strings and the
tokenizer
was renamed to separator
:
plugins:
- search:
separator: '[\s\-\.]+'
lang:
- en
- de
- ru
extra:
search:
language: en, de, ru
tokenizer: '[\s\-\.]+'
extra.social.*
Social links stayed in the same place, but the type
key was renamed to icon
in
order to match the new way of specifying which icon to be used:
extra:
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/squidfunk
extra:
social:
- type: github
link: https://github.com/squidfunk
*.html
filesThe templates have undergone a set of changes to make them future-proof. If you've used theme extension to override a block or template, make sure that it matches the new structure:
base.html
for potential changes*.html
file for
potential changesbase.html
@@ -2,7 +2,6 @@
This file was automatically generated - do not edit
-#}
{% import "partials/language.html" as lang with context %}
-{% set feature = config.theme.feature %}
{% set palette = config.theme.palette %}
{% set font = config.theme.font %}
<!doctype html>
@@ -30,19 +29,6 @@
{% elif config.site_author %}
<meta name="author" content="{{ config.site_author }}">
{% endif %}
- {% for key in [
- "clipboard.copy",
- "clipboard.copied",
- "search.language",
- "search.pipeline.stopwords",
- "search.pipeline.trimmer",
- "search.result.none",
- "search.result.one",
- "search.result.other",
- "search.tokenizer"
- ] %}
- <meta name="lang:{{ key }}" content="{{ lang.t(key) }}">
- {% endfor %}
<link rel="shortcut icon" href="{{ config.theme.favicon | url }}">
<meta name="generator" content="mkdocs-{{ mkdocs_version }}, mkdocs-material-5.0.0">
{% endblock %}
@@ -56,9 +42,9 @@
{% endif %}
{% endblock %}
{% block styles %}
- <link rel="stylesheet" href="{{ 'assets/stylesheets/application.********.css' | url }}">
+ <link rel="stylesheet" href="{{ 'assets/stylesheets/main.********.min.css' | url }}">
{% if palette.primary or palette.accent %}
- <link rel="stylesheet" href="{{ 'assets/stylesheets/application-palette.********.css' | url }}">
+ <link rel="stylesheet" href="{{ 'assets/stylesheets/palette.********.min.css' | url }}">
{% endif %}
{% if palette.primary %}
{% import "partials/palette.html" as map %}
@@ -69,20 +55,17 @@
{% endif %}
{% endblock %}
{% block libs %}
- <script src="{{ 'assets/javascripts/modernizr.********.js' | url }}"></script>
{% endblock %}
{% block fonts %}
{% if font != false %}
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family={{
font.text | replace(' ', '+') + ':300,400,400i,700%7C' +
font.code | replace(' ', '+')
}}&display=fallback">
<style>body,input{font-family:"{{ font.text }}","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"{{ font.code }}","Courier New",Courier,monospace}</style>
{% endif %}
{% endblock %}
- <link rel="stylesheet" href="{{ 'assets/fonts/material-icons.css' | url }}">
{% if config.extra.manifest %}
<link rel="manifest" href="{{ config.extra.manifest | url }}" crossorigin="use-credentials">
{% endif %}
@@ -95,47 +77,50 @@
{% endblock %}
{% block extrahead %}{% endblock %}
</head>
+ {% set direction = config.theme.direction | default(lang.t('direction')) %}
{% if palette.primary or palette.accent %}
{% set primary = palette.primary | replace(" ", "-") | lower %}
{% set accent = palette.accent | replace(" ", "-") | lower %}
- <body dir="{{ lang.t('direction') }}" data-md-color-primary="{{ primary }}" data-md-color-accent="{{ accent }}">
+ <body dir="{{ direction }}" data-md-color-primary="{{ primary }}" data-md-color-accent="{{ accent }}">
{% else %}
- <body dir="{{ lang.t('direction') }}">
+ <body dir="{{ direction }}">
{% endif %}
- <svg class="md-svg">
- <defs>
- {% set platform = config.extra.repo_icon or config.repo_url %}
- {% if "github" in platform %}
- {% include "assets/images/icons/github.f0b8504a.svg" %}
- {% elif "gitlab" in platform %}
- {% include "assets/images/icons/gitlab.6dd19c00.svg" %}
- {% elif "bitbucket" in platform %}
- {% include "assets/images/icons/bitbucket.1b09e088.svg" %}
- {% endif %}
- </defs>
- </svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
- <label class="md-overlay" data-md-component="overlay" for="__drawer"></label>
+ <label class="md-overlay" for="__drawer"></label>
+ <div data-md-component="skip">
+ {% if page.toc | first is defined %}
+ {% set skip = page.toc | first %}
+ <a href="{{ skip.url | url }}" class="md-skip">
+ {{ lang.t('skip.link.title') }}
+ </a>
+ {% endif %}
+ </div>
+ <div data-md-component="announce">
+ {% if self.announce() %}
+ <aside class="md-announce">
+ <div class="md-announce__inner md-grid md-typeset">
+ {% block announce %}{% endblock %}
+ </div>
+ </aside>
+ {% endif %}
+ </div>
{% block header %}
{% include "partials/header.html" %}
{% endblock %}
- <div class="md-container">
+ <div class="md-container" data-md-component="container">
{% block hero %}
{% if page and page.meta and page.meta.hero %}
{% include "partials/hero.html" with context %}
{% endif %}
{% endblock %}
- {% if feature.tabs %}
- {% include "partials/tabs.html" %}
- {% endif %}
+ {% block tabs %}
+ {% if "tabs" in config.theme.features %}
+ {% include "partials/tabs.html" %}
+ {% endif %}
+ {% endblock %}
- <main class="md-main" role="main">
- <div class="md-main__inner md-grid" data-md-component="container">
+ <main class="md-main" data-md-component="main">
+ <div class="md-main__inner md-grid">
{% block site_nav %}
{% if nav %}
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
@@ -160,41 +141,25 @@
<article class="md-content__inner md-typeset">
{% block content %}
{% if page.edit_url %}
- <a href="{{ page.edit_url }}" title="{{ lang.t('edit.link.title') }}" class="md-icon md-content__icon"></a>
+ <a href="{{ page.edit_url }}" title="{{ lang.t('edit.link.title') }}" class="md-content__button md-icon">
+ {% include ".icons/material/pencil.svg" %}
+ </a>
{% endif %}
+ {% block source %}
+ {% if page and page.meta and page.meta.source %}
+ {% include "partials/source-link.html" %}
+ {% endif %}
+ {% endblock %}
{% if not "\x3ch1" in page.content %}
<h1>{{ page.title | default(config.site_name, true)}}</h1>
{% endif %}
{{ page.content }}
- {% block source %}
- {% if page and page.meta and page.meta.source %}
- <h2 id="__source">{{ lang.t("meta.source") }}</h2>
- {% set repo = config.repo_url %}
- {% if repo | last == "/" %}
- {% set repo = repo[:-1] %}
- {% endif %}
- {% set path = page.meta.path | default([""]) %}
- {% set file = page.meta.source %}
- <a href="{{ [repo, path, file] | join('/') }}" title="{{ file }}" class="md-source-file">
- {{ file }}
- </a>
- {% endif %}
- {% endblock %}
+ {% if page and page.meta %}
+ {% if page.meta.git_revision_date_localized or
+ page.meta.revision_date
+ %}
+ {% include "partials/source-date.html" %}
- {% if page and page.meta and (
- page.meta.git_revision_date_localized or
- page.meta.revision_date
- ) %}
- {% set label = lang.t("source.revision.date") %}
- <hr>
- <div class="md-source-date">
- <small>
- {% if page.meta.git_revision_date_localized %}
- {{ label }}: {{ page.meta.git_revision_date_localized }}
- {% elif page.meta.revision_date %}
- {{ label }}: {{ page.meta.revision_date }}
- {% endif %}
- </small>
- </div>
{% endif %}
{% endblock %}
{% block disqus %}
@@ -208,29 +174,35 @@
{% include "partials/footer.html" %}
{% endblock %}
</div>
{% block scripts %}
- <script src="{{ 'assets/javascripts/application.********.js' | url }}"></script>
- {% if lang.t("search.language") != "en" %}
- {% set languages = lang.t("search.language").split(",") %}
- {% if languages | length and languages[0] != "" %}
- {% set path = "assets/javascripts/lunr/" %}
- <script src="{{ (path ~ 'lunr.stemmer.support.js') | url }}"></script>
- {% for language in languages | map("trim") %}
- {% if language != "en" %}
- {% if language == "ja" %}
- <script src="{{ (path ~ 'tinyseg.js') | url }}"></script>
- {% endif %}
- {% if language in ("ar", "da", "de", "es", "fi", "fr", "hu", "it", "ja", "nl", "no", "pt", "ro", "ru", "sv", "th", "tr", "vi") %}
- <script src="{{ (path ~ 'lunr.' ~ language ~ '.js') | url }}"></script>
- {% endif %}
- {% endif %}
- {% endfor %}
- {% if languages | length > 1 %}
- <script src="{{ (path ~ 'lunr.multi.js') | url }}"></script>
- {% endif %}
- {% endif %}
- {% endif %}
- <script>app.initialize({version:"{{ mkdocs_version }}",url:{base:"{{ base_url }}"}})</script>
+ <script src="{{ 'assets/javascripts/vendor.********.min.js' | url }}"></script>
+ <script src="{{ 'assets/javascripts/bundle.********.min.js' | url }}"></script>
+ {%- set translations = {} -%}
+ {%- for key in [
+ "clipboard.copy",
+ "clipboard.copied",
+ "search.config.lang",
+ "search.config.pipeline",
+ "search.config.separator",
+ "search.result.placeholder",
+ "search.result.none",
+ "search.result.one",
+ "search.result.other"
+ ] -%}
+ {%- set _ = translations.update({ key: lang.t(key) }) -%}
+ {%- endfor -%}
+ <script id="__lang" type="application/json">
+ {{- translations | tojson -}}
+ </script>
+ {% block config %}{% endblock %}
+ <script>
+ app = initialize({
+ base: "{{ base_url }}",
+ features: {{ config.theme.features | tojson }},
+ search: Object.assign({
+ worker: "{{ 'assets/javascripts/worker/search.********.min.js' | url }}"
+ }, typeof search !== "undefined" && search)
+ })
+ </script>
{% for path in config["extra_javascript"] %}
<script src="{{ path | url }}"></script>
{% endfor %}
partials/footer.html
@@ -5,34 +5,34 @@
<div class="md-footer-nav">
- <nav class="md-footer-nav__inner md-grid">
+ <nav class="md-footer-nav__inner md-grid" aria-label="{{ lang.t('footer.title') }}">
{% if page.previous_page %}
- <a href="{{ page.previous_page.url | url }}" title="{{ page.previous_page.title | striptags }}" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
- <div class="md-flex__cell md-flex__cell--shrink">
- <i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
+ <a href="{{ page.previous_page.url | url }}" title="{{ page.previous_page.title | striptags }}" class="md-footer-nav__link md-footer-nav__link--prev" rel="prev">
+ <div class="md-footer-nav__button md-icon">
+ {% include ".icons/material/arrow-left.svg" %}
</div>
- <div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
- <span class="md-flex__ellipsis">
+ <div class="md-footer-nav__title">
+ <div class="md-ellipsis">
<span class="md-footer-nav__direction">
{{ lang.t("footer.previous") }}
</span>
{{ page.previous_page.title }}
- </span>
+ </div>
</div>
</a>
{% endif %}
{% if page.next_page %}
- <a href="{{ page.next_page.url | url }}" title="{{ page.next_page.title | striptags }}" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
- <div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
- <span class="md-flex__ellipsis">
+ <a href="{{ page.next_page.url | url }}" title="{{ page.next_page.title | striptags }}" class="md-footer-nav__link md-footer-nav__link--next" rel="next">
+ <div class="md-footer-nav__title">
+ <div class="md-ellipsis">
<span class="md-footer-nav__direction">
{{ lang.t("footer.next") }}
</span>
{{ page.next_page.title }}
- </span>
+ </div>
</div>
- <div class="md-flex__cell md-flex__cell--shrink">
- <i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
+ <div class="md-footer-nav__button md-icon">
+ {% include ".icons/material/arrow-right.svg" %}
</div>
</a>
{% endif %}
partials/header.html
@@ -2,51 +2,43 @@
This file was automatically generated - do not edit
-#}
<header class="md-header" data-md-component="header">
- <nav class="md-header-nav md-grid">
- <div class="md-flex">
- <div class="md-flex__cell md-flex__cell--shrink">
- <a href="{{ config.site_url | default(nav.homepage.url, true) | url }}" title="{{ config.site_name }}" aria-label="{{ config.site_name }}" class="md-header-nav__button md-logo">
- {% if config.theme.logo.icon %}
- <i class="md-icon">{{ config.theme.logo.icon }}</i>
- {% else %}
- <img alt="logo" src="{{ config.theme.logo | url }}" width="24" height="24">
- {% endif %}
- </a>
- </div>
- <div class="md-flex__cell md-flex__cell--shrink">
- <label class="md-icon md-icon--menu md-header-nav__button" for="__drawer"></label>
- </div>
- <div class="md-flex__cell md-flex__cell--stretch">
- <div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
- {% if config.site_name == page.title %}
- {{ config.site_name }}
- {% else %}
- <span class="md-header-nav__topic">
- {{ config.site_name }}
- </span>
- <span class="md-header-nav__topic">
- {% if page and page.meta and page.meta.title %}
- {{ page.meta.title }}
- {% else %}
- {{ page.title }}
- {% endif %}
- </span>
- {% endif %}
+ <nav class="md-header-nav md-grid" aria-label="{{ lang.t('header.title') }}">
+ <a href="{{ config.site_url | default(nav.homepage.url, true) | url }}" title="{{ config.site_name }}" class="md-header-nav__button md-logo" aria-label="{{ config.site_name }}">
+ {% include "partials/logo.html" %}
+ </a>
+ <label class="md-header-nav__button md-icon" for="__drawer">
+ {% include ".icons/material/menu" ~ ".svg" %}
+ </label>
+ <div class="md-header-nav__title" data-md-component="header-title">
+ {% if config.site_name == page.title %}
+ <div class="md-header-nav__ellipsis md-ellipsis">
+ {{ config.site_name }}
</div>
- </div>
- <div class="md-flex__cell md-flex__cell--shrink">
- {% if "search" in config["plugins"] %}
- <label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
- {% include "partials/search.html" %}
- {% endif %}
- </div>
- {% if config.repo_url %}
- <div class="md-flex__cell md-flex__cell--shrink">
- <div class="md-header-nav__source">
- {% include "partials/source.html" %}
- </div>
+ {% else %}
+ <div class="md-header-nav__ellipsis">
+ <span class="md-header-nav__topic md-ellipsis">
+ {{ config.site_name }}
+ </span>
+ <span class="md-header-nav__topic md-ellipsis">
+ {% if page and page.meta and page.meta.title %}
+ {{ page.meta.title }}
+ {% else %}
+ {{ page.title }}
+ {% endif %}
+ </span>
</div>
{% endif %}
</div>
+ {% if "search" in config["plugins"] %}
+ <label class="md-header-nav__button md-icon" for="__search">
+ {% include ".icons/material/magnify.svg" %}
+ </label>
+ {% include "partials/search.html" %}
+ {% endif %}
+ {% if config.repo_url %}
+ <div class="md-header-nav__source">
+ {% include "partials/source.html" %}
+ </div>
+ {% endif %}
</nav>
</header>
partials/hero.html
@@ -1,9 +1,8 @@
{#-
This file was automatically generated - do not edit
-#}
-{% set feature = config.theme.feature %}
{% set class = "md-hero" %}
-{% if not feature.tabs %}
+{% if "tabs" not in config.theme.features %}
{% set class = "md-hero md-hero--expand" %}
{% endif %}
<div class="{{ class }}" data-md-component="hero">
partials/language.html
@@ -3,12 +3,4 @@
-#}
{% import "partials/language/" + config.theme.language + ".html" as lang %}
{% import "partials/language/en.html" as fallback %}
-{% macro t(key) %}{{ {
- "direction": config.theme.direction,
- "search.language": (
- config.extra.search | default({})
- ).language,
- "search.tokenizer": (
- config.extra.search | default({})
- ).tokenizer | default("", true),
-}[key] or lang.t(key) or fallback.t(key) }}{% endmacro %}
+{% macro t(key) %}{{ lang.t(key) | default(fallback.t(key)) }}{% endmacro %}
partials/logo.html
@@ -0,0 +1,9 @@
+{#-
+ This file was automatically generated - do not edit
+-#}
+{% if config.theme.logo %}
+ <img src="{{ config.theme.logo | url }}" alt="logo">
+{% else %}
+ {% set icon = config.theme.icon.logo or "material/library" %}
+ {% include ".icons/" ~ icon ~ ".svg" %}
+{% endif %}
partials/nav-item.html
@@ -14,9 +14,15 @@
{% endif %}
<label class="md-nav__link" for="{{ path }}">
{{ nav_item.title }}
+ <span class="md-nav__icon md-icon">
+ {% include ".icons/material/chevron-right.svg" %}
+ </span>
</label>
- <nav class="md-nav" data-md-component="collapsible" data-md-level="{{ level }}">
+ <nav class="md-nav" aria-label="{{ nav_item.title }}" data-md-level="{{ level }}">
<label class="md-nav__title" for="{{ path }}">
+ <span class="md-nav__icon md-icon">
+ {% include ".icons/material/arrow-left.svg" %}
+ </span>
{{ nav_item.title }}
</label>
<ul class="md-nav__list" data-md-scrollfix>
@@ -39,6 +45,9 @@
{% if toc | first is defined %}
<label class="md-nav__link md-nav__link--active" for="__toc">
{{ nav_item.title }}
+ <span class="md-nav__icon md-icon">
+ {% include ".icons/material/table-of-contents.svg" %}
+ </span>
</label>
{% endif %}
<a href="{{ nav_item.url | url }}" title="{{ nav_item.title | striptags }}" class="md-nav__link md-nav__link--active">
partials/nav.html
@@ -1,14 +1,10 @@
{#-
This file was automatically generated - do not edit
-#}
-<nav class="md-nav md-nav--primary" data-md-level="0">
- <label class="md-nav__title md-nav__title--site" for="__drawer">
- <a href="{{ config.site_url | default(nav.homepage.url, true) | url }}" title="{{ config.site_name }}" class="md-nav__button md-logo">
- {% if config.theme.logo.icon %}
- <i class="md-icon">{{ config.theme.logo.icon }}</i>
- {% else %}
- <img alt="logo" src="{{ config.theme.logo | url }}" width="48" height="48">
- {% endif %}
+<nav class="md-nav md-nav--primary" aria-label="{{ lang.t('nav.title') }}" data-md-level="0">
+ <label class="md-nav__title" for="__drawer">
+ <a href="{{ config.site_url | default(nav.homepage.url, true) | url }}" title="{{ config.site_name }}" class="md-nav__button md-logo" aria-label="{{ config.site_name }}">
+ {% include "partials/logo.html" %}
</a>
{{ config.site_name }}
</label>
partials/search.html
@@ -6,15 +6,18 @@
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
- <input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="{{ lang.t('search.placeholder') }}" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
+ <input type="text" class="md-search__input" name="query" aria-label="{{ lang.t('search.placeholder') }}" placeholder="{{ lang.t('search.placeholder') }}" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" data-md-state="active">
<label class="md-search__icon md-icon" for="__search">
+ {% include ".icons/material/magnify.svg" %}
+ {% include ".icons/material/arrow-left.svg" %}
</label>
- <button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
- 
+ <button type="reset" class="md-search__icon md-icon" aria-label="{{ lang.t('search.reset') }}" data-md-component="search-reset" tabindex="-1">
+ {% include ".icons/material/close.svg" %}
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
- <div class="md-search-result" data-md-component="result">
+ <div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
{{ lang.t("search.result.placeholder") }}
</div>
partials/social.html
@@ -3,9 +3,12 @@
-#}
{% if config.extra.social %}
<div class="md-footer-social">
- <link rel="stylesheet" href="{{ 'assets/fonts/font-awesome.css' | url }}">
{% for social in config.extra.social %}
- <a href="{{ social.link }}" target="_blank" rel="noopener" title="{{ social.type }}" class="md-footer-social__link fa fa-{{ social.type }}"></a>
+ {% set _,rest = social.link.split("//") %}
+ {% set domain = rest.split("/")[0] %}
+ <a href="{{ social.link }}" target="_blank" rel="noopener" title="{{ domain }}" class="md-footer-social__link">
+ {% include ".icons/" ~ social.icon ~ ".svg" %}
+ </a>
{% endfor %}
</div>
{% endif %}
partials/source-date.html
@@ -0,0 +1,15 @@
+{#-
+ This file was automatically generated - do not edit
+-#}
+{% import "partials/language.html" as lang with context %}
+{% set label = lang.t("source.revision.date") %}
+<hr>
+<div class="md-source-date">
+ <small>
+ {% if page.meta.git_revision_date_localized %}
+ {{ label }}: {{ page.meta.git_revision_date_localized }}
+ {% elif page.meta.revision_date %}
+ {{ label }}: {{ page.meta.revision_date }}
+ {% endif %}
+ </small>
+</div>
partials/source-link.html
@@ -0,0 +1,13 @@
+{#-
+ This file was automatically generated - do not edit
+-#}
+{% import "partials/language.html" as lang with context %}
+{% set repo = config.repo_url %}
+{% if repo | last == "/" %}
+ {% set repo = repo[:-1] %}
+{% endif %}
+{% set path = page.meta.path | default([""]) %}
+<a href="{{ [repo, path, page.meta.source] | join('/') }}" title="{{ file }}" class="md-content__button md-icon">
+ {{ lang.t("meta.source") }}
+ {% include ".icons/" ~ config.theme.icon.repo ~ ".svg" %}
+</a>
partials/source.html
@@ -2,24 +2,11 @@
This file was automatically generated - do not edit
-#}
{% import "partials/language.html" as lang with context %}
-{% set platform = config.extra.repo_icon or config.repo_url %}
-{% if "github" in platform %}
- {% set repo_type = "github" %}
-{% elif "gitlab" in platform %}
- {% set repo_type = "gitlab" %}
-{% elif "bitbucket" in platform %}
- {% set repo_type = "bitbucket" %}
-{% else %}
- {% set repo_type = "" %}
-{% endif %}
-<a href="{{ config.repo_url }}" title="{{ lang.t('source.link.title') }}" class="md-source" data-md-source="{{ repo_type }}">
- {% if repo_type %}
- <div class="md-source__icon">
- <svg viewBox="0 0 24 24" width="24" height="24">
- <use xlink:href="#__{{ repo_type }}" width="24" height="24"></use>
- </svg>
- </div>
- {% endif %}
+<a href="{{ config.repo_url }}" title="{{ lang.t('source.link.title') }}" class="md-source">
+ <div class="md-source__icon md-icon">
+ {% set icon = config.theme.icon.repo or "fontawesome/brands/git-alt" %}
+ {% include ".icons/" ~ icon ~ ".svg" %}
+ </div>
<div class="md-source__repository">
{{ config.repo_name }}
</div>
partials/tabs-item.html
@@ -1,7 +1,7 @@
{#-
This file was automatically generated - do not edit
-#}
-{% if nav_item.is_homepage %}
+{% if nav_item.is_homepage or nav_item.url == "index.html" %}
<li class="md-tabs__item">
{% if not page.ancestors | length and nav | selectattr("url", page.url) %}
<a href="{{ nav_item.url | url }}" class="md-tabs__link md-tabs__link--active">
partials/tabs.html
@@ -5,7 +5,7 @@
{% if page.ancestors | length > 0 %}
{% set class = "md-tabs md-tabs--active" %}
{% endif %}
-<nav class="{{ class }}" data-md-component="tabs">
+<nav class="{{ class }}" aria-label="{{ lang.t('tabs.title') }}" data-md-component="tabs">
<div class="md-tabs__inner md-grid">
<ul class="md-tabs__list">
{% for nav_item in nav %}
partials/toc-item.html
@@ -6,7 +6,7 @@
{{ toc_item.title }}
</a>
{% if toc_item.children %}
- <nav class="md-nav">
+ <nav class="md-nav" aria-label="{{ toc_item.title }}">
<ul class="md-nav__list">
{% for toc_item in toc_item.children %}
{% include "partials/toc-item.html" %}
partials/toc.html
@@ -2,35 +2,22 @@
This file was automatically generated - do not edit
-#}
{% import "partials/language.html" as lang with context %}
-<nav class="md-nav md-nav--secondary">
+<nav class="md-nav md-nav--secondary" aria-label="{{ lang.t('toc.title') }}">
{% endif %}
{% if toc | first is defined %}
<label class="md-nav__title" for="__toc">
+ <span class="md-nav__icon md-icon">
+ {% include ".icons/material/arrow-left.svg" %}
+ </span>
{{ lang.t("toc.title") }}
</label>
<ul class="md-nav__list" data-md-scrollfix>
{% for toc_item in toc %}
{% include "partials/toc-item.html" %}
{% endfor %}
- {% if page.meta.source and page.meta.source | length > 0 %}
- <li class="md-nav__item">
- <a href="#__source" class="md-nav__link md-nav__link--active">
- {{ lang.t("meta.source") }}
- </a>
- </li>
- {% endif %}
- {% set disqus = config.extra.disqus %}
- {% if page and page.meta and page.meta.disqus is string %}
- {% set disqus = page.meta.disqus %}
- {% endif %}
- {% if not page.is_homepage and disqus %}
- <li class="md-nav__item">
- <a href="#__comments" class="md-nav__link md-nav__link--active">
- {{ lang.t("meta.comments") }}
- </a>
- </li>
- {% endif %}
</ul>
{% endif %}
</nav>
Material for MkDocs 4 fixes incorrect layout on Chinese systems. The fix includes a mandatory change of the
base font-size from 10px
to 20px
which means all rem
values needed to
be updated. Within the theme, px
to rem
calculation is now encapsulated in a new
function called px2rem
which is part of the SASS code base.
If you use Material for MkDocs with custom CSS that is based on rem
values, note that those
values must now be divided by 2. Now, 1.0rem
doesn't map to 10px
, but
20px
. To learn more about the problem and implications, please refer to #911 in which the problem was discovered and fixed.
mkdocs.yml
None.
*.html
filesNone.
This page includes a list of deprecations, indicating which features of Material for MkDocs were replaced with newer, more flexible alternatives, and thus should not be used anymore.
Deprecated: 5.5.0 · Removal: 6.x
The redirect
key, which could be added via Metadata, allowed to specify a redirect from within a document to
a new address, which is a good idea when moving content around:
---
redirect: /path/to/new/file
---
The redirects plugin provides the ability to
define redirect mappings via mkdocs.yml
, which is considered to be a much better solution to
achieve the same result. It can be installed with pip
:
pip install mkdocs-redirects
Redirect mappings can then be added to mkdocs.yml
:
plugins:
- redirects:
redirect_maps:
path/to/old/file.md: path/to/new/file.md
Deprecated: 5.5.0 · Removal: 6.x
The source
and path
keys, which could be added via Metadata, showed a source icon at the top right corner of a
document, linking a document to a single source file:
---
path: tree/master/docs
source: deprecations.md
---
Only a single source file could be linked, which is useless if a document refers to multiple files (or multiple sections within a single file). A more flexible approach is to use the new icon integration:
[:octicons-file-code-24: Source](https://github.com/squidfunk/mkdocs-material/blob/master/docs/deprecations.md)
This will render as Source, which can be included at arbitrary positions in any document.
Deprecated: 5.5.0 · Removal: 6.x
The hero
key, which could be added via Metadata,
allowed to render a simple, text-only and page-local teaser text as part of a document. It could be set from
front matter with:
---
hero: Lorem ipsum dolor sit amet
---
The recommended way is to override the hero
block via theme extension for a specific page, which
has the nice side effect that hero templates can be shared among multiple pages:
---
template: overrides/hero.html
---
{% block hero %}
<!-- Add custom hero here -->
{% endblock %}