Rendered Gantt Charts with Mermaid, Hugo & Gulp

Rendered Gantt Charts with  Mermaid, Hugo & Gulp

Gantt charts are super popular with project management, and their use in the construction field is no exception. If you’re working with a big team, paid solutions like TeamGannt or Basecamp are good ways to keep track of tasks. But what if you just want a quick way to visualize the near future? Something that can be embedded on your blog. Without JavaScript. For free. Enter Mermaid. With the help of Gulp and Hugo, we can make updating Gantt charts on our web site as simple as saving a text file.

To see this in action, view our construction log.


First things first, install Mermaid. I use npm, so I simply:

cd /Documents/Sites/path_to_my_site
npm install mermaid

Likewise, Mermaid CLI should be installed which allows Mermaid to be run from the command line instead of from JavaScript.

npm install mermaid.cli

// Verify install was succesful:
./node_modules/.bin/mmdc -h

Make note of the ./node_modules... path because it is needed to call the script from Gulp. After that, create a test Gantt chart called timeline.mmd in the same directory. Just copy / paste the example from their documentation. Or, if you want to try your own content, their live editor is a handy tool to mock up charts.

	title A Gantt Diagram
	dateFormat  YYYY-MM-DD
	section Section
	A task           :a1, 2014-01-01, 30d
	Another task     :after a1  , 20d
	section Another
	Task in sec      :2014-01-12  , 12d
	another task      : 24d

Finally, test Mermaid by building it in the command line:

./node_modules/.bin/mmdc -i timeline.mmd -o output.svg
Starting 'mermaid'...
Finished 'mermaid' after 583 ms


Once Mermaid is installed and can be built from the command line, the next step is to build from Gulp. To do that, I’m using gulp-run-command, which allows Gulp to run command line actions. In the same project directory, install with:

npm install gulp-run-command

Now, when our site builds with gulpfile.js, the Gantt charts can be generated. My Gulp task looks like:

var run = require('gulp-run-command').default;
gulp.task('mermaid', run('./node_modules/.bin/mmdc -i timeline.mmd -o themes/journal/layouts/partials/timeline.svg -c mermaid.json', {}));

Every time my site is built, or if I manually test with gulp mermaid, the SVG file will be saved to the path listed. You’ll also notice -c mermaid.json is being passed in. That is for a config file. To use a custom config file, create mermaid.json in the same directory, and start with:

	"gantt": {
		"titleTopMargin": 50,
		"barHeight": 30,
		"barGap": 10,
		"topPadding": 50,
		"sidePadding": 0,
		"gridLineStartPadding": 40

Here is a reference for all config options.


At this point, we have SVG files being written to our directory every time the site is built. Adding the SVG file to your site can be as simple as <img src="timeline.svg" />, but that will not give us full control over styles. For styling, we have to add the actual SVG code. To do that with Hugo, a partial template can be used, but partials can not be included from content pages. So, we’ll use a shortcode instead for content pages. I created gantt.html in /layouts/shortcodes of my Hugo theme.

<div class="inlinePhoto full">
	<figure itemprop="associatedMedia" itemscope itemtype="" class="">
		{{ partial (printf "%s" ( .Get "chart" )) . }}
	            {{ .Get "caption" | markdownify }}

Then, the shortcode is called in a content page with:

{{< gantt chart="timeline.svg" caption="2019-2020 Planning Timeline" >}}

Basically, the file name and caption are passed in. The actual SVG tags are then output, and not just an image. This comes with quite a few benefits:

  • Everything is rendered for a static site – no JavaScript required.
  • Simply edit and save a text file to change the chart content.
  • No separate software to download to manage the charts.
  • The charts can be styled to match the site exactly.
  • By being part of the build process, the charts will be updated whenever anything in the site is touched.

Score one for JAMStack sites!


SVG styles are a bit tricky if you’ve never worked with them before. I found this list of SVG properties to be handy. Then, when it comes to including the actual CSS file, I used my existing CSS structure and added !important tags as needed. The override is required because the SVG outputs with inline CSS, and I could not get the -C option working on the command line tool to provide an override CSS. Your experience may vary. With that in mind, the CSS for this site is:

.titleText, .sectionTitle {
    display: none;

.section {
    fill: white !important;

.taskText, .taskTextOutsideRight {
    @include proseFont();
    line-height: 35px;
    margin-bottom: 0;
    font-weight: 400;
    width: 100%;
    fill: $textBlack !important;

    @include breakpoint(full-screen) {
       line-height: 42px;

.today {
    display: none;

.tick {
    border: 1px solid $black;

.task {
    stroke-width: 0.5 !important;
    stroke: $black !important;
    fill: white !important;

.grid .tick:nth-child(even) {
    //display: none;

.tick line {
    stroke-dasharray: 1;
    opacity: 0.4;


This site documents our attempts to create a dream home. If you enjoy this content, you may want to check out our metrics, construction notes, and progress photos. While you're looking around, you might as well subscribe to our RSS, Mastodon, Twitter, Instagram and YouTube feeds. Or, see if these related posts catch your attention.