Skip to content

How to use Materials for MkDocs on JHPCE web sites

Relationship between Markdown, MkDocs, and Materials for MkDocs

In short: you write Markdown documents and MkDocs turns them into a static web site using the Material for MkDocs theme.

  • Markdown is the lightweight markup language used to write the content (headings, lists, code blocks, etc.).
  • MkDocs is a Python-based static site generator that converts those Markdown files into a documentation website.
  • Material for MkDocs is a theme and feature framework built on top of MkDocs — it layers "Material Design" styling, client-side search, dark mode, code annotations, content tabs, admonitions, and 10,000+ icons/emojis onto the base MkDocs build pipeline.

Material for MkDocs is the most-installed third-party MkDocs theme on PyPI. It makes sites look and behave professionally, without any custom CSS or JS (although you can override things with custom CSS (and we do a little of that).

Overview

Material for MkDocs is a software ecosystem which allows one to create static web pages from Markdown documents. (Because only static web pages are supported, Mark Miller had to develop a way to use Google Forms to support dynamic pages e.g. new user form.)

By "ecosystem" we mean that there is a core software suite created by an "Squidfunk" organization which is extended by libraries/plugins created by both Squidfunk and the Internet community. All of the components have version numbers and are enhanced over time. We use only free features. If we paid a yearly fee, we would have have access to a larger set of features. (Keep that in mind when reading documention -- often there are cryptic icons next to a feature and you must know that you cannot use those.)

We use a GitHub repo jhpce-jhu/jhpce_mkdocs repository to hold and serve the web site's files. That repository also contains configuration and programs which make the web site function. The repository contains Materials for Mkdocs Python packages.

We do not have a list of what high level changes to a default repository were needed. This will make it challenging to create a new repo for a new web site, or recover if we attempt to upgrade the software and the effort explodes in our face.

Making changes to the web site

JHPCE web site contributors can edit the web site's pages in a web browser or by using git to work with the site's files.

If you use git, you can decide to install and run a mkdocs Python program on your computer. You use mkdocs to run a local HTTP server which will process MkDocs files as they are modified. Doing that allows you to create documents and/or significantly revise them without affecting the active web site. A local mkdocs server section is included.

Vital operational things for systems administrators to know:

  1. You can check on the status of rebuilding the web site in the Workflows section.
  2. You must include rebuild-site in the Git commit comment when you want the web site to be re-generated.

Productively using Material for MkDocs

Material for MkDocs is packed with many great features that make technical writing a joyful activity.

Let's create a visually appealing web site using some of these features!!

There are two other related documents:

  • Please consult the Tips and Conventions page for JHPCE-specific authoring guidance and tips.
  • There is another document containing wishlist items that we might want to enable/configure.

Jeffrey recommends these features in particular:

Critical Material for MkDocs reference material

Look here for information about these and other features!!! Just keep in mind that ones marked "insiders" are not available for our use. Materials for MkDocs reference section.

It isn't clear how much caution one should use in consulting MkDocs documents and people's solutions for it. JRT thinks that Material for MkDocs differs enough that one should definitely keep in mind whether your google search has turned up something about MkDocs.

Modifying text patterns across the site

Example of changing all markdown files in a copy of the git repo:

cd jhpce_mkdocs
find . -type f -name \*.md -exec grep -il "www.jhpce.jhu.edu" {} \;
find . -type f -name \*.md -exec sed -i '' "s/www.jhpce.jhu.edu/jhpce-old.jhu.edu/g" {} \;
find . -type f -name \*.md -exec grep -il "jhpce-old.jhu.edu" {} \; | xargs git add

Admonitions (vertically open-by-default colored blocks)

(These don't render correctly in MacDown.app)

Admonitions are a kind of code block which begins with three !+!+! marks.

These are sweet! We should use them frequently. Be aware that they are not rendered correctly in the Mac program MacDown.app. This is an example of where it is good to be running "mkdocs serve" on your local machine. So you can verify that they are properly constructed before you push up your modified markdown file.

Consider whether or not you want the material collapsed or expanded when users first visit a page. If you want the information collapsed, create a "detail" instead of an "admonition" by using question marks instead of exclamation points. Details are described here.

<a href="https://squidfunk.github.io/mkdocs-material/reference/admonitions/"" target="_blank">Admonition documentation

You add an admonition by

  1. Having a blank line preceeding the admonition
  2. starting a line with three ! explanation marks, a space, and a keyword (called a "type qualifier") such as note, danger, example, info, tip, warning. Here is a list. Certain colors are used for known keywords. If you use your own word or phrase, the color is maybe out of your control.
  3. You can add an optional title for your admonition by adding a double quoted string after the type qualifier.
  4. on the next line(s) start with FOUR spaces. You can have multiple paragraphs inside your admonition by continuing to indent the first line by FOUR SPACES.

Note

Some text using the "note" type qualifier

Example

admonitions allow setting off info inside colored boxes, e.g. note, tip, warning, danger, example. https://squidfunk.github.io/mkdocs-material/reference/admonitions/#usage

All lines indented four spaces are included in your admonition, including fenced code blocks.

Code block inside of an admonition

Show my failed jobs between noon and now
sacct -s F -o "user,jobid,state,nodelist,start,end,exitcode" -S noon -E now

Details (vertically collapsed-by-default colored blocks)

(These don't render correctly in MacDown.app)

Details are a kind of code block which begins with three ?+?+? marks.

Like an admonition but makes pages more readable by collapsing content. You can nest details, and choose to display them open or closed. Documentation here and also explained in the detail below.

Psst: Click To Expand

Details are by default closed. You can have it rendered to be open -- users can collapse it, if they wish, for example to hide that info after they've read it. The following "detail" was set in the Markdown to display as already opened up.

Syntax to use

Details must contain a blank line before they start.

Usage: ?+?+? [type_qualifier] "Words to display for this detail"

Use ??? to start a details block or ???+ if you want to start a details block whose default state is 'open'.

Follow the start of the block with an optional class keyword (like "tip" or "warning") or classes (separated with spaces) and the summary contained in double quotes.

After the header line which creates the detail block, add your content.

Every line of the content must be indented with FOUR SPACES.

Nesting:

Another detail can be nested inside the first by adding another blank line, another detail header line and its content block. But this header line needs to include the class_keyword "multiple".

You can probably include code blocks inside of detail blocks like you can with admonitions.

Content Tabs (horizontally-collapsed colored tabs)

(These don't render correctly in the MacDown.app macOS program Jeffrey uses.)

Tabs are a kind of code block which begins with three =+=+= marks.

These are very neat. They allow you to create a horizontal set of headings. Clicking on each heading causes a different set of content to appear. This can save A LOT of vertical page space. It is intuitive for readers to click on what they need.

Places you would use content tabs: You want to describe how something differs between two clusters, show the steps to do the same activity on three different operating systems, or show the equivalent code for four different programming languages.

Here is the core tabs documentation.

Tabs are created with similar syntax as admonitions or details:

  • There must be a blank line before the beginning of a (admonition, detail, tab).
  • The first line consists of: three punctuation marks Space
  • Everything else inside the visual block must be indented FOUR SPACES (not a tab char!!!) inside of (admonition, detail, tab)
  • You MUST enclose the title of the tab in double quotes even if it is a single word (it seems to Jeffrey)

Simple example of content tabs

This example contains one or two lines of text. The default tab is the left-most, and whichever one you click on becomes rendered in bold font. I fooled around and made the second tab italicized, for contrast.

More intuitive and elegant

The lesser way. What Microsoft forces upon you.

Respect your elders. It was all we had for a LONG TIME.

Really, a long time. At least we Generation X-ers had calculators instead of slide rules.

Content tabs inside of admonitions or details

Everything has to be indented FOUR SPACES (not a tab char) inside of the tab you are creating

So when inside of an (admonition, detail, tab) therefore tab contents are all indented EIGHT spaces. (Yes, you can have tab blocks inside of tab blocks. Never tab characters though!!!)

These two examples contain tab blocks inside of a detail and an admonition:

Details are collapsed (by default)
Contents for Mac users
Contents for Mac users

Admonitions are always expanded

Each tab contains a block of text. Here we've added programming language specifier keywords.

Contents for C++ code

#include <iostream>

int main() {
std::cout << "Hello World!";
return 0;
}

print('Hello, world!')

Discussion about bash code

usage()
{
echo "Usage: $0 [-h] "
echo "Displays all defined QOS with nice formatting."
echo "Caution, this script may not show all fields relevant/used in future."
echo "    -h     |--help        display usage"
}

Frontmatter

The beginning of a document can contain a special section called frontmatter. This is important tool to know exists, as the directives placed here can impact how the page is rendered and how the page is dealt with inside the website (you can exclude pages from search results and other such exceptions or page-specific modifications).

This documentation is not a complete list of frontmatter directives, but it is a start.

You can define the page's title here (otherwise it will be guessed at by considering the first words of a file, such as the first header section (by header I mean denoted with a pound sign).

Page tags are a primary use of frontmatter I think we will use. Tags are a list of keywords which can be used to find pages during searches, e.g. "in-progress" or "needs-correcting".

An example of changing the appearance of the page is to control how many levels of a page's sections are included in a Table of Contents. Or to not display the page in the websites Table of Contents.

An example of changing the page's handling in the website is a frontmatter directive which causes an icon to be displayed next to the page's name in the website's navigation sidebar.

Frontmatter consists of a pair of three dashed lines, with directives between them. Example:

---
tags:
  - a-tag
toc_depth: 2
icon: material/eye
title: some docs need explicit titles set b/c they can't be correctly guessed from page content
hide:
- toc
---

Page Tags

An example of frontmatter is the code to add tags to documents. a page which made a list of tags and the pages which used them using a particular string. (On 20251220 I cannot remember if it worked or not. I thought that it did work. But we no longer see the tags on pages, so perhaps whatever change Makr made to hide the tags also prevents the tag-generation code fail.) See comments in mkdocs.yml's navigation section for notes.

A lot of optional tag-related settings/capabilities seem to be reserved for paying sponsers as of 20240201. See this page. Can users search for documents by tags in the search field?

Some tags I envision using at the outset are shown below, so we can try to use them to figure out which pages need attention and possibly who volunteered or was assigned to finish it.

The tag "needs-improvement-later" could be added to a page which has "done" to indicate that what we have is able to be published but needs more work.

The tag "contains-refs-to-old-site" came to me because some pages, such as the R page, contain screenshots which contain the URL of the old web site.

The tag "last-revised-YYYYMMDD" could be used on a page which also has "done" or "needs-improvement-later" so you can tell that information by looking at the tags page. As opposed to having to go look at the repository. The wishlist document mentions adding a plugin or extension which allows the last-revised date to be automatically generated and listed at the bottom of each page.

Place lines like this at the very top of the document, before the document title, to add the tags mentioned. Tags are strings but I am hoping to avoid spaces or underscores. (Underscores suck b/c they require the shift key. And you can't always see them depenind on how text renders.)

Code blocks can be numbered or not by default (given settings in mkdocs.yml). THEY ARE NOW OFF BY DEFAULT. See this section for instructions on adding titles to code blocks and enabling or disabling line numbering.

---
tags:
  - done
  - needs-review
  - in-progress
  - needs-improvement-later
  - contains-refs-to-old-site
  - last-revised-20240210
  - jeffrey
  - mark
  - jiong
  - adi
  - brian
---

TOC - Generating Table of Content

Clarification: The site navigation bar on the left side is not dynamically generated -- one must edit mkdocs.yml to change that. Settings in that file control how deep TOCs go (toc_depth, currently 5) and also, importantly, set permalink: true. This adds an anchor link to each section of a doc.

This might be the core TOC document.

Each page that defines more than one section (using pound signs) will automatically have a TOC displayed in the right sidebar.

Optional directives can be made in the frontmatter section to control how toc's are handled, such as hiding them altogether or specifying a document-specific depth level.)

You can also add an automatically-generated Table of Contents to a page by inserting at any point "[TOC]".

From this mkdocs page JRT learned that you can specify anchor points to document sections by knowing that they are converted to lowercase and white space is replaced by dashes. So this very section, named "Internal links" can be specified as a link to "../ourtools/features.md#internal-links" (in a different document) or "#internal-links" (inside the same document).

Anchor link addresses are generated automatically for each section because of a setting in mkdocs.yml.

Open URLs in new tabs

(Adi has configured the server to always open URLs in new tabs.)

JRT thinks there might be plugins which make this easier than what you have to do othwerwise, which is to use HTML instead of the Markdown notation. In normal HTML you add a space and a string to the end of the URL: target="_blank"

<a href="https://squidfunk.github.io/mkdocs-material/reference/admonitions/" target="_blank">About admonitions</a>

Working with image files

Key information for doing things like aligning, adding captions, ...

https://squidfunk.github.io/mkdocs-material/reference/images/

There is no center alignment. You can fake it by adding a caption to the image (see example in above page)

Alight to the left or right like this
![Image title](https://dummyimage.com/600x400/eee/aaa){ align=left }
Hmmm, if Jeffrey tries to use that syntax then the rest of the text in this document is placed to the right of the image, even including the next section ("Keyboard meta keys"). How do you indicate a break between the text that you want wrapped on the right and the rest of the document?

This first example places the image to the left (without any align option)

![Image title](../files/images/dir-stack-push-pop.png)
Image title

This second example places the image to the left (without any align option), puts the text I want to the right of it (but no more text!!!)

![Image title](../files/images/dir-stack-push-pop.png) The text that you want to the right side of image.

Image title The text that you want to the right side of image.

This third example results in the whole rest of the document wrapped up to the right of the image. (So I didn't actually put the live code in the document).

![Image title](../files/images/dir-stack-push-pop.png){align=left} The text that you want to the right side of image.

Symbols for keyboard keys

(enabled by the pymdownx.keys extension)

You can create images of keyboard keys, such as meta keys like Ctrl or Cmd by surrounding a keyword such as "ctrl" with two plus characters

+ + ctrl + + will create Ctrl

This can be useful when trying to draw attention to important small characters like back ticks, exclamation marks or vertical pipe symbols. You can also use them as tags like Mail some-address@bob.edu or Help some-URL

DO NOT USE ANY CAPITAL LETTERS or the symbol will not display! Instead you will see only the word you typed. "Ctrl" will fail, "ctrl" will succeed.

EXAMPLES: Menu Up [ ] Caps Lock Eject Fn F4

Key sequences

You can create a meta-key sequence by adding a single + between the keywords. (So you surround the sequence with two plus symbols but only use a single plus symbols in between the keywords.)

Ctrl+Alt+Del is created with + + ctrl + alt + delete + +

List of keywords

Example keywords are: bar, pipe, enter, shift, dblquote, ctrl, esc, tab, space, del, arrow-up, single-quote, brace-left, bracket-right, cmd, windows.

A backtick ` is called a grave, by the way. As in the French "accent grave"

All of the symbols you could desire are listed in the following web page, (except for some reason the vertical "pipe" or "bar" symbol -- use + + pipe + + to create that):

https://facelessuser.github.io/pymdown-extensions/extensions/keys/

Custom "KEYS"

You can create a key (or key combo) with any wording you want by adding double quotes around your text, for example

+ + " Your Wording Here " + + to create Your Wording Here

This can be useful to make a series of steps users need to follow more clear. Do this first+Then do this second

Abbreviations

Abbreviations can be defined by using a syntax similar to URLs and footnotes, starting with an asterisk immediately followed by the term to be associated in square brackets.

This code creates the sentence that follows. You can hover over "HTML" and see the definition appear.

The HTML specification is maintained by the W3C.
*[HTML]: Hyper Text Markup Language

The HTML specification is maintained by the W3C.

Footnotes

This1 is a reference to the feature's description.

You add a footnote by entering

[^1]

in the midst of your text. Anywhere in the document afterwards you create the footnote contents by

  • after a blank line
  • placing at the start of a line
  • the corresponding numbered entry using the same syntax
  • but adding a colon and a space character after the closing square brace, then
  • adding your wording for the footnote.

[^1]: Wording of footnote

Numbering: It seems to be the case that you can use whatever number you want in your Markdown and Materials for MkDocs will generate the correct numbering in the resulting HTML files. In other words, you could give each footnote the number "1" Perhaps this depends on the ordering of the use of a footnote and its definition. (The only algorithm available to the processing is going to be to associate the first use with the first definition, the second use with the second definition, ...)

Glossary

There's a way to create a document which is automatically updated when people define abbrieviations. See the wishlist document for details. Currently we have a manually written glossary, because that was quicker, and allows for the explanation to be longer than many page authors would probably provide in their individual pages.

Definition List (Indenting blocks of text for a topic)

You can create an indented block of text using a colon followed by FOUR space characters.

Example code and result:

`a sample term to define`
:    The definition you are seeking. (But not the droids.)

a sample term to define
The definition you are seeking. (But not the droids.)

Data tables

Tables are easily constructed out of vertical pipe symbols |, hyphens - and text. Optional colons can be used to align column contents.

They don't render unless you also include the line of hyphens under the line containing the column titles.

A simple table is created with these characters:

| Column1 Title | Column2 Title |

| ---------- | ---------- |

| Contents C1R1 | Contents C2R1 |

| Contents C2R1 | Contents C2R2 |

Table Tips:

  • Number of pipe symbols per line must match.
  • Number of hyphens in the second line do not have to match any column width.
  • Alignment is done by placing a colon to the left, right, or on both sides of the hyphens in your dividing line.
    • First column aligned left, second aligned right: | :---------- | ----------: |
    • First column no alignment, second aligned center: | ---------- | :----------: |

Sortable tables

This is now implemented.

https://squidfunk.github.io/mkdocs-material/reference/data-tables/#sortable-tables

Import CSV or Excel file

See https://timvink.github.io/mkdocs-table-reader-plugin/

Diagramming with Mermaid

mkdocs.yml contains code enabling the use of a JavaScript tool called Mermaid. If you want your local mkdocs serve program to be able to display it, you need to pip install mkdocs-mermaid2-plugin (see recipe at bottom of this page)

Material for MkDocs Diagrams documentation

Diagram syntax from the mermaid people

A live editor at the mer-people site!!! You can copy the resulting code to your buffer or save the image as (png,svg).

graph LR
   A[Your computer] --> B[Login nodes]
   B[Login nodes] --> C[(Compute nodes)]

Supported types: flowchart (aka graph), sequenceDiagram, stateDiagram-v2,classDiagram, erDiagram

JRT finds these types interesting: timeline, user journey

Numerous others, including pie, bar and line charts (xychart-beta)

Only some types officially supported by Material for MkDocs

Besides the diagram types listed above, Mermaid.js provides support for pie charts, gantt charts, user journeys, git graphs and requirement diagrams, all of which are not officially supported by Material for MkDocs. Those diagrams should still work as advertised by Mermaid.js, but we don't consider them a good choice, mostly as they don't work well on mobile. While all Mermaid.js features should work out-of-the-box, Material for MkDocs will currently only adjust the fonts and colors for flowcharts, sequence diagrams, class diagrams, state diagrams and entity relationship diagrams.

ICONS and EMOJOIS: Examples: Kinds of check marks

JRT found that these three kinds of check marks are examples of "icons" and "emojis".

Example Markdown text
:material-check:
:material-close:
:material-check-all:

They would not render until I added these three lines to mkdocs.yml:

  - attr_list
  - pymdownx.emoji:
      emoji_index: !!python/name:material.extensions.emoji.twemoji
      emoji_generator: !!python/name:material.extensions.emoji.to_svg

See this page for more information and links to the "icon sets" as well as other pages that display a bazillion emojis: https://squidfunk.github.io/mkdocs-material/reference/icons-emojis/

😄 works if you enter :smile:

STILL UNKNOWN - CAN ANYONE FIGURE IT OUT AND UPDATE THIS PAGE???

But these other things didn't work. For some of them I downloaded an .svg file for them and placed them in both a top-level .icons/ directory and a docs/.icons/ directory. So read more if you want to be able to put all kinds of cool symbols in our pages. DO YOU NEED TO HAVE .ICONS DIRECTORIES AT ALL?

:page-facing-up:

:mdiDatabaseSettingsOutline:

:mdiOrderAlphabeticalAscending:

:fa-regular fa-envelope:

Fenced code blocks

Note that you can set off a block of text using three preceding and three following backtick characters. If you provide a valid keyword immediately after the backticks (no space char), then your code block will have a set of formatting choices applied to them. That keyword could be, for example, python.

Code blocks can be located inside of details and admonitions and probably other things (because of settings added to mkdocs.yml)

There are MANY options for code blocks. All kinds of syntaxes can be used to mean different things. Here is the main document for code blocks.

code block line numbers & highlighting

Code blocks can be numbered or not by default (given settings in mkdocs.yml). THEY ARE NOW OFF BY DEFAULT. See this section for instructions on adding titles to code blocks and enabling or disabling line numbering.

If line numbers are enabled by default, you can disable them for a specific code block by adding after the beginning three back ticks a space, then a linenums="0"

If line numbers are disasbled by default, you can enable them for a specific code block by adding after the beginning three back ticks a space, then a linenums="N" where N is a (?positive?) integer other than zero.

If you have multiple code blocks and want the line numbers to continue in second and later blocks, you can replace that "N" with a specific number.

You can highlight specific line numbers within the block by adding after the beginning three back ticks a space, then a hl_lines="2 3"

code block titles

Add a title by following leading 3 backticks with a space and title=".browserslistrc"

code block formatting by programming language

!!! note: The language keywords are not the same as in github -- there is overlap but also differences. See this list for the language keywords for the Pygments Python syntax highlighter used by Material for MkDocs.

Text written before learning about the above:

Like in Github you can specify a programming language keyword immediately following the leading three backticks to cause the text to be formatted in that language's notation.

There is a directory full of examples you can simply click on.

Useful keywords include Awk, checksums, DNS Zone, Jupyter Notebook, Python, R, Regular Expression, Rich Text Format, SAS, Shell, sed, SSH Config/filenames, stata, YAML

A python example

def fn():
pass

Highlighting text

Some reference resources

code blocks are a critical thing to understand in Materials for MkDocs. They are used for all kinds of formatting, not just highlighting a small number of words!!!!!!

https://squidfunk.github.io/mkdocs-material/reference/formatting/#highlighting-text

https://squidfunk.github.io/mkdocs-material/setup/extensions/python-markdown-extensions/#caret-mark-tilde

Highlighting is extremely useful!!!!

There are tools which make collaborating on revising documents possible. You can also use them for emphasis.Text can be deleted and replacement text added. You can show replacement of old text with new text likethis operation. Comments can be added inline.

Formatting can also be applied to blocks by putting the opening and closing tags on separate lines. Doing this requires you to add a blank line between the content and the beginning and ending tags.

Making the specific characters required to implement these things visible to you in this document:

I could not figure out how to escape the characters involved in highlighting so they would be displayed instead of rendered. Therefore I made use of another feature, which is where you can tell Materials for MkDocs to display icons for keyboard keys.

Highlight a passage by starting with

{ = =

and end with

= = }

Delete text by starting with

{ - -

and ending with

- - }

Add Replacement text by starting with

{ + +

and ending with

+ + }

This can also be combined using tildes and greater-than characters. See the markdown source code onea single.

and comments can be added inline by starting with

{ > >

and ending with

< < }

Snippets: Including other files

Required to enable this feature

Added stanza to mkdocs.yml:

  - pymdownx.snippets: # adds the ability to embed content from arbitrary files into a document
      check_paths: false # if true, if snippets cannot be found, the site cannot be rebuilt!!!
      base_path: docs

When Snippets is enabled, HTML or Markdown content from other files (including source files) can be embedded by using the --8<-- (scissors) notation directly from within a code block to pull in a file via a relative path (starting inside of docs/, not relative to the document doing the including), in this case ourtools/includes/sample-bashrc

It can be extremely frustrating figuring out what path to use to make a snippet actually display. If you get it wrong in certain ways it will prevent the rebuilding of the whole site.

sample bashrc
# System-wide .bashrc file for interactive bash(1) shells.
if [ -z "$PS1" ]; then
     return
fi
For more details about snippets, including ability to pull in only certain sections of other documents, or to append a file to every page in the web site, see https://facelessuser.github.io/pymdown-extensions/extensions/snippets/

This warning says to not enable snippets for security reasons. I cannot discern the threat level to us in our usage. https://github.com/facelessuser/pymdown-extensions/security/advisories/GHSA-jh85-wwv9-24hv

Recipe for Running Mkdocs Locally

Causing the web site to display your modifications

When you push modified files up from your personal computer to the repository, your commit comment MUST INCLUDE the string "rebuild-site". When pages are committed and that string is present, a GitHub Action runs a program ci.yml

If you're doing a lot of edits or want to review changes before you commit them to the web site, it is very useful to be able to do that on your local machine.

To quickly develop pages, and to review your content before you modify the actual web site, you can use a WYSIWYG MarkDown editor and a local copy of the MkDocs website generator. You do not have to commit changes until you are ready.

MacDown is an Mac editor, and displays standard MarkDown (some of the Material for MkDocs functionality is not rendered properly.)

You can install the mkdocs package via python pip here is the recipe, and run mkdoc subcommand to rebuild a local copy of the web site ("mkdocs build") and/or serve it with local web server ("mkdocs serve"). When you are in "serve" mode, mkdocs will watch for changes in your repository and kick off site rebuilds. (Control-C it if you are making many changes, as it scurries off to rebuild after every change it notices. It takes most of a minute to regenerate our site. So you won't see the final result until after the last rebuild, many minutes later.) Mkdocs very helpful displays error messages it finds in your website definition (mkdocs.yml) and the pages themselves.

As of 20251211 these steps are needed to build and start a local Material for MkDocs server that will run a browser at http://127.0.0.1:8000/

JRT thinks that the OS involved was macOS 12 (Monteray) or 14 (Sonoma).

Warning

You will errors & warnings when using mkdocs serve. This happens for two general reasons: because your python set up doesn't include the required packages to handle some document content, or because of GitHub issues, such as being unable to find Git supporting files/directories.

cd ~/Documents/GitHub/

# Clone the repo
# Depending on how you authenticate when pushing files to the repo

git clone https://github.com/jhpce-jhu/jhpce_mkdocs
# or you can use the ssh-key method:
git clone git@github.com:jhpce-jhu/jhpce_mkdocs

# If you want to use ssh keys, then before you can push you need to:
# Generate a GitHub-specific key
# Add that key to your GitHub account (https://github.com/settings/keys)
# Have that key loaded in your ssh agent
# Possibly, run this command to define origin correctly:
# git remote set-url origin git@github.com:jhpce-jhu/jhpce_mkdocs.git

cd jhpce_mkdocs/docs/

# Edit in the docs/ subdirectory, not in sites/ (the latter is where
# the web pages are built by an Action configured in the repo's
# underlying configuration if your commit includes 'rebuild-site')

cd docs/

# These packages should be the same as what is found in the `ci.yml`
# script found in the repo under "Actions". That file actually controls
# how the site is built.

pip3 install mkdocs-material
pip3 install mkdocs-git-revision-date-localized-plugin
pip3 install mkdocs-open-in-new-tab
pip3 install mkdocs-mermaid2-plugin
pip3 install mkdocs-git-authors-plugin
pip3 install mkdocs-extract-listings-plugin
pip3 install mkdocs_table_reader_plugin

#
# Build a directory full of processed files - and view them
#

mkdocs build  # Mainly useful to get a list of errors & warnings

mkdocs serve  # This will both build and serve

# Review your changed document in browser at `http://127.0.0.1:8000/`

# (Note this is not a "https" URL)

# Several options are available for the 'serve' subcommand, such as:
mkdocs serve --dirty
mkdocs serve --dirty -w <dir_to_watch> [-w <2nd_dir_to_watch>]
# --dirty means: Only re-build files that have changed
# You can see the --serve options with: mkdocs serve --help

# Modify the website, by for example, creating a new directory under docs
mkdir newsection

# create a MarkDown document bob.md inside newsection/
vi newsection/bob.md # or use whatever editor you prefer

2026 - it used to be that the running "mkdocs serve" process would wait until you
wrote out changes from your editor to disk. Now, for Jeffrey at least using MacDown,
the _slightest_ change to the file will lead to the serve process regenerating the
entire tree. EVERY TIME you twitch a finger. To work around this, once he gets a
gander at the existing or revised page in his web browser, he control-Z's
"mkdocs serve" until he is done with a bunch of edits. Then he resumes to see the
results. And so on. I checked -- it wasn't because I was using `--dirty`

#
# Add revised files and commit them
#
git add newsection/bob.md
git -m "rebuild-site My_descriptive_text"

git push

# If you cannot push b/c someone else changed the repo since your last pull
git pull --rebase
git push

Errors You Might Run Into Running Mkdocs Locally

2025-04-09 - MM found insalling and running "mkdocs serve" using instructions above on Mac gave constant stream of errors:

INFO    -  DeprecationWarning: Call to deprecated method findAll. (Replaced by find_all) -- Deprecated since
           version 4.0.0.
             File
           "/Users/mmill116/Library/Python/3.9/lib/python/site-packages/mkdocs_extract_listings_plugin/html_parser.py",
           line 18, in parse_listings_from_html
               for pre in soup.findAll('pre'):
             File "/Users/mmill116/Library/Python/3.9/lib/python/site-packages/bs4/_deprecation.py", line 56,
           in alias
               warnings.warn(
The fix was to edit ..../Library/Python/3.9/lib/python/site-packages/mkdocs_extract_listings_plugin/html_parser.py and change the single instance of "findAll" to "find_all".

It can sometimes be useful to Ctrl+C the mkdocs serve program and restart it. Usually this involves significant changes to mkdocs.yml and those will stop over time. However when in doubt give it a try.

JRT added some instructions to the mkdocs.yml file causing warnings to be issued. JRT has found them very useful.

# https://www.mkdocs.org/user-guide/configuration/#validation
validation:
  omitted_files: warn
  absolute_links: warn
  unrecognized_links: warn

The mkdocs serve program will spew out a number of warnings and error messages as you change files. Most of them are important but a few of them are going to recur and are harmless. For example warnings about files in the docs/ tree which are not mentioned in the nav bar. Such files are only going to grow in number. Perhaps there is a way to exclude known cases?

This error means you have an error in frontmatter YML code somewhere
TypeError: '<' not supported between instances of 'NoneType' and 'str'
ERROR   -  [14:46:28] An error happened during the rebuild. The server will appear
           stuck until build errors are resolved.

MacDown WYSIWYG Editor

Jeffrey has found that the free MacDown editor is VERY HELPFUL in authoring. It is a MarkDown editor for the Macintosh which displays the source code in one pane and the rendered document in another pane opposite.

It renders most of Material for MkDocs material correctly, but not all. This is another reason why it is useful to run "mkdocs serve" locally, so you can see in a web browser the results of your edits.

There are preferences that are worth enabling. This page lists the MarkDown elements which are enabled and disabled by default. This page discusses extended syntax and the site has other interesting MarkDown reference information.

One handy feature: If you copy a web URL, highlight some text in your source code, then click on the link insert symbol in the toolbar, it will automatically paste in the URl as it inserts the square brackets and parentheses to create a URL.

Does automatic pattern matching for syntax. Includes a command line program to use to open documents (Jeffrey configured his Mac using Get Info on an .md file to use MacDown by default so he can say in Terminal "open file.md" and it opens up the GUI). Supports a variety of themes for those who like dark mode.

One flaw in this program is that sometimes the source code pane is blank when you open existing documents. The solution is to quit the program and launch it again. The fast workaround is to grow and shrink the document width and the dividing line between the source and rendered document panes.

You can install it by download via the web or with Homebrew with brew install --cask macdown Stats on its page indicate some popularity.

Page Status Icons

These icons show up in the nav bar. You can add icons to pages in two ways by modifying the frontmatter of a page. These can be nice to signal users that some page is important, or that it was under heavy construction.

Basic documentation for this: https://github.com/squidfunk/mkdocs-material/blob/master/docs/reference/index.md

Page Icons

One is by defining an "icon"in the frontmatter for each document.

This appears to the left of the page title in the nav bar. I'd rather it be on the right!!!

There are MANY interesting icons you can use.

Page Status

One is by defining a "status" in the frontmatter for each document But the only three icons available are LAME LAME LAME in both resolution and appeal

You can define a new icon to go with a status, but how to do that in the css file (docs/stylesheets/extra.css) isn't clear to me.

This page goes the furthest to document exactly how to do this, although they used this to define the word BETA rather than using an icon.

See also https://squidfunk.github.io/mkdocs-material/customization/#additional-css


  1. https://squidfunk.github.io/mkdocs-material/reference/footnotes/#adding-footnote-references ↩