Search results

Creating links in DITA versus Jekyll

Series: Jekyll versus DITA

by Tom Johnson on Apr 6, 2015
categories: dita jekyll

In this ongoing series, I'm comparing tech comm techniques with DITA versus Jekyll, a popular static site generator. How you create links is more than a simple technical detail. Linking is one of the main strategies for connecting and interrelating information.

How to create links in DITA

In DITA, you have several choices for making links. You can create a cross reference to another topic like this:

<xref href="sample.dita"/>

The name of the topic will be pulled in when you build your output.

To link to an external web page with an inline link, you add some attributes that let the build system know the page is an external site:

<xref href="" scope="external" outputclass="external" format="html"></xref>

Another way to create links to internal topics is through key references. You can create a link in your DITA map that stores a key value (keydef), and then use that key value for each of your links, using the keyref attribute. I call these keyref-style links. Here's what you might put in your ditamap file for the key:

<keydef href="argument_acme.dita" keys="argument" />

Then refer to it in a topic like this:

<xref keyref="argument"/>

The advantage of keyref-style links is that if you change the reference in the ditamap, you only have to update the value for the key in one place. You won't need to do a global find and replace to change the value.

If you want to manually specify related links below a topic, you can add them using related-links element:

    <link href="sample1.dita"><linktext>Sample 1 Page</linktext></link>
    <link href="sample2.dita"/>
    <link href="sample3.dita"/>

Most of the link methods I mentioned don't align with the total extensibility model for DITA. Although you can create links using these methods, really the recommended way of creating links with DITA is through relationship tables.

A relationship table creates a list of pages that are all related to each other through their placement in the table. Based on the relationships established in the table, links to the other pages appear at the bottom of each page.

Relationship tables allow you to create different outputs without worrying about whether the pages you link to are included in the output. If the page isn't included in the output, the link simply doesn't appear in the relationship table.

Here's a sample relationship table that defines link relationships between pages. (You would put this in your ditamap.)

   <relcolspec type="concept">
   <relcolspec type="task">
   <relcolspec type="reference">
          <topicref href="sample_concept.dita"/>
<p>        <relcell>
          <topicref href="task_example1.dita"/>
          <topicref href="task_example2.dita"/>
          <topicref href="referencefile.dita"/>

It may make more sense to actually show the table in its display form:

Concept Task Reference




In this relationship table, sample_concept.dita will have links to task_example1.dita, task_example2.dita, and referencefile.dita because they're in the same row.

However, task_example1.dita and task_example2.dita will not have links to each other because they're in the same cell.

If you want topics in the same cell to link to each other, add the attribute collection-type="family" to the relcell element that contains the topics you want to link to each other.

Although relationship tables give you a single place to manage all the links for your project, the links pose usability issues. Users are accustomed to seeing links in the same place where the reference appears in the text.

For example, suppose you say, "You can learn more about configuration options by consulting the configuration settings." With a relationship table you wouldn't put the link to configuration settings in that sentence (nor would you even indicate that there is a link to configuration settings).

Instead, you would put the link at the bottom of the page and hope the reader finds it. However, since it's at the bottom of a page, users may not see the link, especially if the page is long.

Without question, the most usable placement for a link is at the spot where you mention the reference. Additionally, links receive some of their page-rank from their anchor text and surrounding keywords, so by pushing the link to the bottom of the page, you lose some Google rank for the keyword.

When I was authoring in DITA, relationship tables never worked for me. I guess I never had so many differing outputs that I needed to resort to relationship tables to make sense of all the links. And I never felt like the usability losses were worth the efficiency gains.

How to create links in Jekyll

Since you can create links in Markdown or HTML with Jekyll, I'll show both methods.

Regardless of whether you're using HTML or Markdown, in the Jekyll configuration file, you must first specify a url and baseurl. These URLs are where you publish your help site. Jekyll will insert these values into every link when you build the site. (And the site will only render properly on the site configured for the url and baseurl specified in the configuration file.)

For example, suppose the website where I would publish the site was In this case, would be the url and /acmehelp would be the baseurl. Each link needs to have the baseurl, which is used as a variable used in constructing each link.

Here's a sample link with Markdown:

{% highlight html %} [Sample]({{ "/sample" | prepend: site.baseurl }}) {% endhighlight %}

Alternatively, you can add the URL references like footnotes:

{% highlight html %} [Sample][1]

[1]: {{ "/sample" | prepend: site.baseurl }} {% endhighlight %}

Here's how you create a link with HTML:

    <a href="{{ "/sample" | prepend: site.baseurl }}">Sample</a>

Note that the reference doesn't automatically pull in the page title like DITA does. This is unfortunate. (But there's somewhat of a workaround that I'll show below.)

If you're linking to an external file, the code is simpler:


And with HTML:

<a href="">Sample</a>

Suppose you want to create keyref-style references, where you manage all the links in a file that each link points to. You could create a data file called links.yml and put values in it like this:

 title: Sample Page
 url: /sample/

Then you could reference the link using Markdown syntax like this:

    [{{}}][1]. </p>
<p>[1]: {{site.baseurl}}{{}}

This is actually the approach I'm using. It's a bit cumbersome, but managing the links and titles in one place helps me avoid broken links.

There is no relationship-table equivalent for links with Jekyll. Jekyll probably wasn't explicitly designed to support the scenario that DITA was designed for (that is, creating many distinct outputs with some pages included in some but not all outputs).

However, you can tag pages and then link to those tags. Tags accomplish a somewhat similar result as a relationship table, though tags function and operate a bit differently. If the tagged page isn't included in the output, the page won't appear on the tag-view page -- same as a relationship table. But tags show their list of pages on their own tag-view archive page.

To add a tag to a page, add it in the frontmatter like this:

title: Configuration
permalink: /config/
tags: configuration

Then modify your page layout to generate a tag linking to a tag-archive page:

{% for tag in page.tags %}
{% if contains tag %}
<a href="{{site.baseurl}}/tag-{{tag}}"><button type="button" class="btn btn-default navbar-btn">{{tag}}</button></a>
{% endif %}
{% endfor %}

Here I'm using a for loop to iterate through all the tags listed in a page's frontmatter. With each tag, I'm first checking whether the tag is listed in my approved list of tags in my tags.yml data file (I add this to ensure the tags aren't created willy-nilly but actually have some thought and consistency.) Then each tag is added to the page in a Bootstrap button-style format.

Related pages

You could also use the same tag logic to create a list of related pages based on tags. You could output the related pages list below each page. Here's some code to do that:

{% for tag in page.tags %}
{% assign counter = '0' %}
{% for page in site.pages %}
{% if page.tags contains tag and page.title != currentTitle and counter < '5' %}
{% capture counter %}{{ counter | plus:'1' }}{% endcapture %}
<li><a href="{{ page.permalink + "/index.html" | prepend: site.baseurl }}">{{page.title}}</a></li>
{% endif %}
{% endfor %}
{% if counter == '0' %}<span class="noOtherPages"><p>No other pages.</p></span>
{% endif %}
{% endfor %}

This code gets the tags on a page, and then uses a for loop to look through each page in the site. If the page has tags that include the tag on the current page, the page is listed here.

There's a problem with this logic, though. Suppose page 1 has tags A and B, page 2 has tags A and B, and page 3 has tags and B. When page 1 looks for all other pages that contain tag A, page 2 and page 3 get listed. That's fine. When the same for loop checks for pages containing tag B, page 2 and page 3 also get listed. In other words, I have to include logic to remove duplicates.

I'm not quite sure how to do that yet, though I'm guessing that a solution exists. Part of why I like Jekyll, though, is because I can piece together the logic I want. There are probably a dozen different approaches I could use for related pages.

At the heart of Jekyll is this near-infinite extensibility. You can do a lot of different things because you have access to the code, and you can use templating logic in the same pages as your content.


I've never used any system that made it easy to handle links. But I do think that tagging provides some interesting advantages to DITA-style links.

A previous commenter noted that you can do more with DITA than the Open Toolkit processes. We just have to wait for vendors to catch up with platforms to do more sophisticated processing (perhaps creating tags based on properties in a topic's metadata). I guess that could be the case, but I like being able to use my own little coding skills to hack together a solution in an afternoon.

Tags start to be more important when your content scales to the point where a TOC becomes useless. The relationship table might work up to a point, but suppose you have thousands of pages. For example, with all the posts on my blog, any kind of TOC or relationship table would be a joke. About the only way to manage content that consists of thousands of topics is through search and tagging.

About Tom Johnson

Tom Johnson

I'm an API technical writer based in the Seattle area. On this blog, I write about topics related to technical writing and communication — such as software documentation, API documentation, AI, information architecture, content strategy, writing processes, plain language, tech comm careers, and more. Check out my API documentation course if you're looking for more info about documenting APIs. Or see my posts on AI and AI course section for more on the latest in AI and tech comm.

If you're a technical writer and want to keep on top of the latest trends in the tech comm, be sure to subscribe to email updates below. You can also learn more about me or contact me. Finally, note that the opinions I express on my blog are my own points of view, not that of my employer.