__Material 5 Beta 3 is here! See deploy preview.__
This will be the last beta before the first RC. The API can be considered stable, so from this beta on no big changes should be expected to the HTML or CSS.
__Please post any problems you encounter during migration in this issue.__
pip install "mkdocs-material>=5.0.0b3"
__material.dialog$.next("Hi!") in the console!Material 5 includes some long awaited but breaking changes. The migration guide will help you switch to the latest version.
mkdocs.ymlFollowing is a list of changes that need to be made to your mkdocs.yml. Note that you only need to adjust the values if you defined them. Click on the options to see examples.
theme.feature โ theme.features
__Material 4.x__
theme: feature: tabs: true
__Material 5.x__
theme: features: - tabs - instant
theme.logo.icon โ theme.icon.logo
__Material 4.x__
theme: logo: icon: cloud
__Material 5.x__
theme: icon: logo: material/cloud
extra.repo_icon โ theme.icon.repo
__Material 4.x__
extra: repo_icon: gitlab
__Material 5.x__
theme: icon: repo: fontawesome/brands/gitlab
extra.search โ plugins.search
__Material 4.x__
extra: search: language: en, de, ru tokenizer: [\s\-\.]+
__Material 5.x__
plugins: - search: separator: '[\s\-\.]+' lang: - en - de - ru
extra.social..type โ extra.social..icon
__Material 4.x__
extra: social: - type: github link: https://github.com/squidfunk - type: twitter link: https://twitter.com/squidfunk - type: linkedin link: https://www.linkedin.com/in/squidfunk
__Material 5.x__
extra: social: - icon: fontawesome/brands/github-alt link: https://github.com/squidfunk - icon: fontawesome/brands/twitter link: https://twitter.com/squidfunk - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/squidfunk/
*.html filesThe templates have undergone a set of necessary changes to make them future-proof. If you've used theme extension to override a template block or HTML file, make sure that the structure of the HTML matches the new structure.
base.html for potential changes*.html file for potential changes
base.html
diff --git a/material/base.html b/material/base.html
index f26b7283..34340f8c 100644
--- a/material/base.html
+++ b/material/base.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,21 +29,8 @@
{% 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.0b2-1">
{% endblock %}
{% block htmltitle %}
{% if page and page.meta and page.meta.title %}
@@ -56,9 +42,9 @@
{% endif %}
{% endblock %}
{% block styles %}
- <link rel="stylesheet" href="{{ 'assets/stylesheets/application.adb8469c.css' | url }}">
+ <link rel="stylesheet" href="{{ 'assets/stylesheets/main.14bb5ffa.min.css' | url }}">
{% if palette.primary or palette.accent %}
- <link rel="stylesheet" href="{{ 'assets/stylesheets/application-palette.a8b3c06d.css' | url }}">
+ <link rel="stylesheet" href="{{ 'assets/stylesheets/palette.f5f04e6f.min.css' | url }}">
{% endif %}
{% if palette.primary %}
{% import "partials/palette.html" as map %}
@@ -68,25 +54,22 @@
<meta name="theme-color" content="{{ primary }}">
{% endif %}
{% endblock %}
{% block libs %}
- <script src="{{ 'assets/javascripts/modernizr.86422ebf.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 %}
{% for path in config["extra_css"] %}
<link rel="stylesheet" href="{{ path | url }}">
{% endfor %}
{% block analytics %}
{% if config.google_analytics %}
@@ -95,47 +78,46 @@
{% 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>
{% if page.toc | first is defined %}
- <a href="{{ (page.toc | first).url }}" tabindex="0" class="md-skip">
+ {% set skip = page.toc | first %}
+ <a href="{{ skip.url | url }}" class="md-skip" data-md-component="skip">
{{ lang.t('skip.link.title') }}
</a>
{% endif %}
+ {% if self.announce() %}
+ <aside class="md-announce" data-md-component="announce">
+ <div class="md-announce__inner md-grid md-typeset">
+ {% block announce %}{% endblock %}
+ </div>
+ </aside>
+ {% endif %}
{% 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 +142,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" %}
+ {% endif %}
+ {% endblock %}
- {% 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,40 @@
{% include "partials/footer.html" %}
{% endblock %}
</div>
+ {% block config %}
+ <script>var __config={}</script>
+ {% endblock %}
{% block scripts %}
- <script src="{{ 'assets/javascripts/application.df00da5d.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.31a2e7b9.min.js' | url }}"></script>
+ <script src="{{ 'assets/javascripts/bundle.5b33ad8d.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>
+ <script>
+ __material = initialize(Object.assign({
+ url: {
+ base: "{{ base_url }}",
+ worker: {
+ search: "{{ 'assets/javascripts/worker/search.edc88caf.min.js' | url }}"
+ }
+ },
+ features: {{ config.theme.features | tojson }}
+ }, __config))
+ </script>
{% for path in config["extra_javascript"] %}
<script src="{{ path | url }}"></script>
{% endfor %}
partials/footer.html
diff --git a/material/partials/footer.html b/material/partials/footer.html
index c2f5a1c0..ca248f62 100644
--- a/material/partials/footer.html
+++ b/material/partials/footer.html
@@ -7,32 +7,32 @@
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
{% 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
diff --git a/material/partials/header.html b/material/partials/header.html
index cfaf1a3b..90438e8c 100644
--- a/material/partials/header.html
+++ b/material/partials/header.html
@@ -3,50 +3,44 @@
-#}
<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 %}
+ <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 %}
+ <img src="{{ config.theme.logo | url }}" alt="logo">
+ {% else %}
+ {% include ".icons/" ~ config.theme.icon.logo ~ ".svg" %}
+ {% endif %}
+ </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">
+ <div class="md-header-nav__ellipsis md-ellipsis">
+ {% if config.site_name == page.title %}
+ {{ config.site_name }}
+ {% else %}
+ <span class="md-header-nav__topic">
{{ 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 %}
- </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" %}
+ </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 %}
</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>
- </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
diff --git a/material/partials/hero.html b/material/partials/hero.html
index 3d6a2cc8..2c244e18 100644
--- a/material/partials/hero.html
+++ b/material/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
diff --git a/material/partials/language.html b/material/partials/language.html
index d0314ffc..46188a6b 100644
--- a/material/partials/language.html
+++ b/material/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/nav-item.html
diff --git a/material/partials/nav-item.html b/material/partials/nav-item.html
index 54c06034..15e626ab 100644
--- a/material/partials/nav-item.html
+++ b/material/partials/nav-item.html
@@ -8,15 +8,21 @@
{% if nav_item.children %}
<li class="{{ class }} md-nav__item--nested">
{% if nav_item.active %}
<input class="md-nav__toggle md-toggle" data-md-toggle="{{ path }}" type="checkbox" id="{{ path }}" checked>
{% else %}
<input class="md-nav__toggle md-toggle" data-md-toggle="{{ path }}" type="checkbox" id="{{ path }}">
{% 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" 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>
@@ -32,13 +38,16 @@
{% elif nav_item == page %}
<li class="{{ class }}">
{% set toc_ = page.toc %}
<input class="md-nav__toggle md-toggle" data-md-toggle="toc" type="checkbox" id="__toc">
{% if toc_ | first is defined and "\x3ch1 id=" in page.content %}
{% set toc_ = (toc_ | first).children %}
{% endif %}
{% 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
diff --git a/material/partials/nav.html b/material/partials/nav.html
index b72383d4..0735f58e 100644
--- a/material/partials/nav.html
+++ b/material/partials/nav.html
@@ -2,12 +2,12 @@
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>
+ <label class="md-nav__title" for="__drawer">
+ <a href="{{ config.site_url | default(nav.homepage.url, true) | url }}" title="{{ config.site_name }}" aria-label="{{ config.site_name }}" class="md-nav__button md-logo">
+ {% if config.theme.logo %}
+ <img src="{{ config.theme.logo | url }}" alt="logo">
{% else %}
- <img alt="logo" src="{{ config.theme.logo | url }}" width="48" height="48">
+ {% include ".icons/" ~ config.theme.icon.logo ~ ".svg" %}
{% endif %}
</a>
{{ config.site_name }}
partials/search.html
diff --git a/material/partials/search.html b/material/partials/search.html
index 4863b708..4510355b 100644
--- a/material/partials/search.html
+++ b/material/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" aria-label="search" name="query" 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="search" placeholder="{{ lang.t('search.placeholder') }}" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" data-md-state="active" required>
<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" 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
diff --git a/material/partials/social.html b/material/partials/social.html
index 391385e5..8b4ebdfe 100644
--- a/material/partials/social.html
+++ b/material/partials/social.html
@@ -3,9 +3,10 @@
-#}
{% 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>
+ <a href="{{ social.link }}" target="_blank" rel="noopener" class="md-footer-social__link">
+ {% include ".icons/" ~ social.icon ~ ".svg" %}
+ </a>
{% endfor %}
</div>
{% endif %}
partials/source-date.html
diff --git a/material/partials/source-date.html b/material/partials/source-date.html
new file mode 100644
index 00000000..9c72b8bc
--- /dev/null
+++ b/material/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
diff --git a/material/partials/source-link.html b/material/partials/source-link.html
new file mode 100644
index 00000000..86418fa1
--- /dev/null
+++ b/material/partials/source-link.html
@@ -0,0 +1,17 @@
+{#-
+ 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([""]) %}
+{% set file = page.meta.source %}
+{% set repo_icon = config.extra.repo_icon | default(
+ "fontawesome/brands/git-alt"
+) %}
+<a href="{{ [repo, path, page.meta.source] | join('/') }}" title="{{ file }}" class="md-content__button md-icon">
+ {{ lang.t("meta.source") }}
+ {% include ".icons/" ~ repo_icon ~ ".svg" %}
+</a>
partials/source.html
diff --git a/material/partials/source.html b/material/partials/source.html
index 742d42de..a65295a4 100644
--- a/material/partials/source.html
+++ b/material/partials/source.html
@@ -2,24 +2,10 @@
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">
+ {% include ".icons/" ~ config.theme.icon.repo ~ ".svg" %}
+ </div>
<div class="md-source__repository">
{{ config.repo_name }}
</div>
partials/tabs-item.html
diff --git a/material/partials/tabs-item.html b/material/partials/tabs-item.html
index 1f3179d3..64ced43b 100644
--- a/material/partials/tabs-item.html
+++ b/material/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/toc.html
diff --git a/material/partials/toc.html b/material/partials/toc.html
index 14a5e070..db4cfbea 100644
--- a/material/partials/toc.html
+++ b/material/partials/toc.html
@@ -3,34 +3,21 @@
-#}
{% import "partials/language.html" as lang with context %}
<nav class="md-nav md-nav--secondary">
{% set toc = page.toc %}
{% if toc | first is defined and "\x3ch1 id=" in page.content %}
{% set toc = (toc | first).children %}
{% 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>
The basic idea is: why should we reconstruct the whole page again and again when only the content and navigation changes? When instant loading is enabled, all internal links are intercepted and dispatched via XHR. The resulting document is parsed, injected and all event handlers are automatically rebound. The search index will remain intact in-between loads.
With instant loading enabled, Material effectively behaves like a Single Page Application.
This feature shows the true beauty of the new architecture - everything is observable and automatically updates when new values become available. The following gifs were recorded on Fast 3G to show the speed advantage of instant loading:
Without instant loading

With instant loading

FontAwesome was updated to the latest version and is now provided via inline SVGs which reduces the overall footprint. To reference an icon, reference its path from the top-level .icons directory which is distributed with the theme without the .svg at the end. Besides FontAwesome, the Material icons and GitHub's octicons are also bundled with the theme.
Note that mkdocs build will now terminate with an error if an invalid icon is referenced.
direction="None" when no direction is set 584eac86__Feedback is appreciated!__
@squidfunk just started testing this and looks good so far!
A few thoughts:
Bad value None for attribute dir on element body.git iconEverything else seems to work fine from my testing so far ๐ค
@XhmikosR thanks for reporting!
Seems to be related to an invalid default value of config.theme.direction. Should have no impact on usage, but should be easy to fix
Yep, the default icon now is just the git icon. To change it see the original post - it can now be changed to any icon!
Yep, the default icon now is just the git icon. To change it see the original post - it can now be changed to any icon!
All good, I changed it already, I was wondering if the change was intentional :)
Another thing I noticed is that there are some new Lighthouse issues (ignore the page is blocked and canonical errors): https://lighthouse-dot-webdotdevsite.appspot.com//lh/html?url=https://deploy-preview-275--pihole-docs.netlify.com/
Also, I was wondering, have you thought about loading the search index file when the search form is focused or something like that, instead of page load?
There's a lot of noise in the Lighthouse report. Could you isolate what you mean specifically? The link titles? We should definitely fix them.
Regarding the search index โ we could load it on focus, but then we'll have a delay and I don't want to do that at least until we have a loading indicator. I would try to leave it as is for the initial release and if it leads to problems or people complain we can delay it (or even introduce an option whether to load on page load or on interaction).
@facelessuser reported a problem on Gitter (which currently gives me 504) where sometimes, when instant loading is enabled, the URL would double, so a link click on ./installation/ would resolve to ./installation/installation. This is caused by the first request being served with a 304 which the theme currently doesn't recognize as a successful XHR (due to no response body) and will fallback to regular loading which then doubles the entry because in MkDocs, all internal links are relative. I added it to the list of known bugs in the OP and will provide a fix in a post release.
return (navigator.userAgent.indexOf("MSIE ") > -1 || navigator.userAgent.indexOf("Trident/") > -1);
file:// protocol) would be nice. If not, never mind.@wilhelmer regarding 1., I would like to leave it up to the user. Maybe we'll integrate something into the theme later, but I don't want to force a specific way onto users. Also, some people may decide they want to support IE. Regarding 2., that's actually a good idea. We could detect the file:// protocol and omit the repository info loading and instant loading altogether.
The race condition which @facelessuser reported and direction=None were fixed and released as part of 5.0.0b3-2. Upgrade with:
pip install --upgrade --force-reinstall "mkdocs-material>=5.0.0b3"
There's a lot of noise in the Lighthouse report. Could you isolate what you mean specifically? The link titles? We should definitely fix them.
I meant these:
a elements without margin between them, so the links are very close to one another)Could you craft a PR so we can discuss some potential fixes? Unfortunately I have too much stuff on my plate to finally get v5 out of the door.
I'll see what I can do because I'm not familiar with your development process (but shouldn't be too hard judging from a quick look). I can make a separate issue if you want to track the Lighthouse issues in the meantime, although these are issues specific to v5.0.0.
BTW if v5 doesn't support IE, you can probably remove <meta http-equiv="x-ua-compatible" content="ie=edge">
The templates in question are located in the src folder (not material), so just included your changes there. You may also remove the IE-compat header ๐
Is there an example of using the custom CSS stuff to change colors? It looks like I have to build a CSS file with color definitions in it and somehow tell mkdocs to use that CSS? Looks like there's nothing in the docs about it yet either. If I had an example I could probably reverse engineer and maybe even add some stuff to the docs about it.
@FISHMANPET I linked the definitions in the original post; here it is again:
You can just copy those definitions in an extra CSS file and override only those which you need.
Iโll provide an example in the new documentation when I find some time.
I'll play around with it a bit, and this may be my complete inexeperience with CSS or HTML showing, but it doesn't seem to be behaving the way I would expect. I copied that block, and got it loaded using extra_css. When I open developer view I can see Chrome has loaded my css file. But even if I leave them as default, the ones I'm interested in aren't valid, and show like this in the style viewer:

Mousing over the yellow triangle it says Unknown Property Name.
OK there's... some kind of issue, possibly with character encoding, in what I've copied. This didn't work:
// Primary color shades
--md-primary-fg-color: hsla(348, 100%, 24%, 1);
--md-primary-fg-color--light: hsla(#{hex2hsl($clr-indigo-300)}, 1);
This does:
// Primary color shades
--md-primary-fg-color--light: hsla(#{hex2hsl($clr-indigo-300)}, 1);
--md-primary-fg-color: hsla(348, 100%, 24%, 1);
The "unknown property" is always the element after the comments, If I move the element I care about (in this case md-primary-fg-color) to not be the first element after the comment, it's accepted. So odds are good this is my fault somehow, an issue of how I copy pasted or character encoding or something like that.
The original source is compiled with SCSS, a preprocessor, and references non-CSS functions. As values you should just use normal CSS colors, e.g. #FF0000
OK, it was an issue with my lack of knowledge around CSS. I wasn't having a problem with the color definitions, CSS will accept hsla(348, 100%, 24%, 1);. The problem is that SCSS comments are different from CSS comments, so just copy and pasting what you'd defined didn't work, I either have to remove all the comments, or replace // comment with /* comment */.
And hex2hsl function doesn't work, so any of those that are used have to be taken out. I think I understand this enough, I might try and document it myself.
Small issue: If tabs is set to false, .md-header has a shadow, but that shadow is added _after_ FMP, through data-md-state="shadow". That causes some jitter, or at least looks a little jittery.
Could you provide a screen recording showing the issue? It should be pretty much the same as with the current version.
Note the header shadow when I keep pressing F5:

That's the same for Material 4, isn't it?
It should be - the CSS seems identical. But somehow, it doesn't flicker when using v4. ๐ค
I get the exact same "flickering" on v4. The header shadow is actually applied after it's loaded because the header might be above the tabs. Since the tabs come after the header there's no way of telling from CSS alone if we need to show the shadow or not, so it must be determined based on scroll offset.
This is the result of pressing reload for v4 on latest Chrome, macOS:

Another one: When adding the features option to mkdocs.yml, I get a console error, and search doesn't work. (Using latest version in refactor/rxjs-typescript)
mkdocs.yml:
site_name: My Docs
theme:
name: material
features:
tabs: true
Console error:
TypeError: t.features.includes is not a function
index.ts:151:36
@wilhelmer the config format has changed, see "Changes to mkdocs.yml" in the OP.
I'm currently reworking the docs, so the v5 docs should shortly be available as part of the v5 deploy preview.
Uuuh, it's not only the plural s, it's also the added dash before tabs. Tricky.
Well, I thought I documented it precisely enough. I'm sorry for the config changes but a major version is a good reason to finally clean some stuff up.
It probably is, but people are blind ๐
That's why I wrote a step-by-step migration guide. It'll be part of the docs. If you feel it could be improved, I'm happy to merge PRs.
This one is probably hard to debug, but there are strange things going on with the prebuilt index.
When I set prebuild_index to true or python, I often get weird or missing search results.
For example, look at this search for "hardware". Up to "hardwar", there are some search results, but the top results are already missing (there should be pages like "Hardware Installation" on top of the list). Then, when I type "hardware", I suddenly get no results at all:

This does not happen with the MkDocs default theme, and also not with prebuild_index set to false.
Unfortunately, I can't provide you with my sources. Maybe you can fire up the King James bible project to reproduce that?
Probably related to differences in the pipeline used to produce the index (Python) and load the index (JavaScript). Material alters the pipeline, so it might be related to that. What happens if you set this line:
to stemmer, trimmer, stopWordFilter?
No difference.
Have you rebuilt the theme so the changes propagated to the material folder?
I added the file (en.html) to my custom_dir. Also changed a language string for visual check, and the language string changed.
Okay. Could you try to isolate the problem? Support for prebuilt indexes is actually quite new so I expect that there're some problems yet to be discovered with this being the first one.
Another thing that comes to my mind that could be related - Material automatically adds trailing wildcards and does some post-processing on the search query before submitting it to the index. This is not done in the MkDocs documentation. To see what Material does to the query before submitting it, type this into your console:
__material.search$.subscribe(({ query }) => console.log(query))
... and then take the exact same query and enter it in the original MkDocs theme. This will give you:

Interesting. If I enter "hardware*" in the original MkDocs theme, I get 0 results. So that probably causes the error.
That was my point. The search UX in the original theme is very suboptimal as the search results "dance" a lot when entering a search term. This is why Material uses wildcards. However, it may be interesting to know why this is happening but this seems to be something related to Lunr.
Apparently, a search for "hardware*" excludes results with "hardware". It expects at least 1 char matching the wildcard.
Maybe always use searchterm* searchterm?
When I search for color or metadata on the Material docs, it includes those specific results, even though there is no further character.
Did you search with prebuild_index set to true?`
Side note: Maybe fuzzy match is an alternative? A search for hardware~1 in the original theme yields the correct results, and it also works as kind of a wildcard when using hardw~1
Hmm, metadata works when setting it to prebuild_index: true, but some other terms yield worse results. We can improve on this topic after version 5 is out. Prebuilt indexes were not supported before so support should be considered experimental anyways.
Okay, the entire lunr syntax doesn't work for me when using prebuild_index. Neither +foo nor -bar nor foo*. And because Material uses the wildcard internally, the search results get screwed up.
There will be a possibility to completely disable the search query preprocessing but for most of the cases it yields the best results.
@wilhelmer could you open an issue once v5 is out on this topic which provides a minimal, reproducible test case, ideally with a mint MkDocs repository that shows the issue? v5 is already packed with so much stuff so we definitely have to postpone that post-release.
Aye ๐
BTW, as the search worker implementation is configurable, there's the option to replace search with a completely custom implementation, if you're not happy with search. Just provide an alternative worker script to the template and adhere to the message structure. This also opens the possibility to use an entirely different backend like ElasticSearch or some SaaS service.
Modified the theme to replace all * in search queries with ~1. Runs fine now ๐
The problem with fuzzy search is that it is much more computationally intensive than wildcard search and yields worse results on average.
Might be related to stemming, see here: https://github.com/olivernn/lunr.js/issues/256
(No need to reply, just saving this for later.)
... ah, and there the reason why we removed the stemmer from the pipeline in the first place comes back to my mind. Regarding stemming we must distinguish two cases:
With stemming enabled you cannot use wildcards which will make the search "jumpy" or return no results at all except for completely entered search terms. Try to search for search on the official MkDocs page. IMHO this is rather bad search UX, as a good typeahead is expected for every search interface we encounter, because, well, Google. The counter argument is that you can always add a wildcard to your search, but from a practical perspective this would mean that you enter a wildcard, then press ArrowLeft and then enter your search term. Material does this automatically for a reason.
With stemming disabled you can use wildcards, but then the prebuilt search index must also be built with stemming disabled, or hardware will stem to hardwar and the search for hardware will return no results. The information is essentially lost during the building stage.
From the top of my head I can think of no other way than patching the generation of the search index to not use the stemmer. Unfortunately, the pipeline seems not to be configurable for when the index is prebuilt.
However, the transformation function should be overridable via configuration when the final version of v5 is released, so you can always disable the wildcard search by overriding the following function:
Okay. So that function is not overridable right now, but will be until the final version of v5?
Yes, or probably with 5.1. However, if you fork the theme you can change it to your liking as of now.
And the alternative is adding an option to the official search plugin to make the lunr pipeline configurable, especially for prebuilt indexes, e.g.:
- search:
prebuild_index: python
pipeline:
- stemmer: false
- trimmer: true
- stopWordFilter: true
@waylan Is that possible / on the roadmap / worth opening an issue for?
@waylan Is that possible / on the roadmap / worth opening an issue for?
Please feel free to open an issue. At a minimum that gives us a place to track this and document any decisions we make. There is a lot of good stuff in this discussion, but it also contains a lot of noise (all the non-search stuff). So a summary would be helpful in a MkDocs issue along with a link to this issue.
Superseded by #1498 โ thanks to all testers!