Skip to content

Theme docs

Components

The Markdown shortcodes, with copyable examples.

Reusable pieces you can call from inside Markdown. Every one is an include in _includes/components/, and every one renders classes that are already in the stylesheet — so they inherit the theme’s colours, spacing and dark mode without a line of extra CSS.

See them all rendered at /style-guide/, which is a real page in the site — if a component breaks, it breaks visibly there on the next build.

A note on the comma-separated arguments. Several components take a list as "a|b,c|d" rather than as YAML. That is not a stylistic choice: Liquid includes cannot accept a nested data structure, and this is the shape that works inside a Markdown file. If an item needs a literal comma, escape it as %2C.


Callout

{% include components/callout.html type="warning"
   title="Governor limits apply"
   text="This runs inside a trigger, so the SOQL is inside a loop you cannot see." %}

type: note (default) · info · success · warning · danger

Each type is a promise about what is inside it. A warning that turns out to be a tip teaches readers to skip the next one, so pick by the consequence of ignoring it, not by which colour looks best.

For anything longer than a sentence or two, wrap Markdown directly — the markdown="1" attribute is what lets kramdown keep processing inside the div:

<div class="tb-callout tb-callout--info" markdown="1">
Multiple paragraphs, lists and fenced code all work in here.
</div>

Button

{% include components/button.html label="Read the docs" url="/docs/" %}
{% include components/button.html label="Download" url="/x.pdf" style="primary" icon="download" %}
{% include components/button.html label="Source" url="https://github.com/…" style="ghost" external=true %}
Parameter Values
style primary, secondary, ghost (default), soft, quiet, danger
size sm, lg
icon Any name from the icon sprite
external true — adds rel="noopener", a new tab, and says so
block true — full width

external=true announces “opens in a new tab” to a screen reader. A link that changes context without warning is the most common avoidable accessibility bug on a personal site.


Stats

{% include components/stats.html items="99.98%|Uptime,1.3s|Page load,40+|Orgs" %}

value|label, comma-separated. Four is the maximum that still reads as a headline; a fifth turns it into data, and data belongs in a table.


Steps

{% include components/steps.html items="Create a scratch org|Takes about ninety seconds.,Push the source|`sfdx force:source:push`,Assign the permission set|Otherwise nothing is visible." %}

title|body, comma-separated. Numbers are drawn by CSS from a counter, so inserting a step in the middle does not mean renumbering the rest. The body accepts inline Markdown.

For a procedure with real code in it, write an ordered list with fenced blocks instead — this is for short, scannable sequences.


Tabs

{% include components/tabs.html id="install"
   items="Bundler|Add the gem to your Gemfile.,Remote theme|Set `remote_theme:` in _config.yml." %}

label|body, comma-separated. id must be unique on the page — it namespaces the radio group, and two tab sets sharing an id will fight.

Built from real radio inputs, so arrow keys, tab order and the focus ring come from the platform, and the first panel is visible before any script runs.

Use tabs only for genuine alternatives — three ways to install the same thing. Sequential content in tabs is content most readers will see a third of.


Accordion

{% include components/accordion.html open_first=true
   items="Does it work on GitHub Pages?|Yes — every plugin is allowlisted.,Do I need Node?|No." %}

question|answer, comma-separated. open_first=true opens the first one.

Built on <details>, so it works without JavaScript and needs no ARIA of its own. Do not put anything a reader needs behind one — a collapsed answer is an answer most people will not read.


Video

{% include components/video.html id="dQw4w9WgXcQ" title="Deploying with scratch orgs"
   caption="Optional line underneath." %}

Loads from YouTube’s no-cookie domain, lazily, in a box that reserves its own 16:9 space so the article does not jump when the iframe arrives.

title is required by the include on purpose: an untitled iframe is announced as “frame” and nothing else.


Icons

{% include icon.html name="cloud" %}
{% include icon.html name="mail" class="tb-icon--md" label="Email" %}

Decorative by default. Pass label only when the icon is the only thing naming a control — an icon beside the word “Email” that also has a label is read out twice.

Sizes: tb-icon--md, tb-icon--lg, tb-icon--xl.

Available: cloud, cloud-user, badge, shield, pen, code, layers, mic, book, quote, list, user, briefcase, graduation, map-pin, search, sun, moon, x, check, arrow-right, arrow-left, arrow-up-right, external, copy, download, printer, share, link, tag, calendar, clock, mail, database, zap, sparkle, star, play, lightbulb, info, alert, check-circle, x-circle, inbox, github, linkedin, mastodon, rss, youtube, bluesky.

Add your own by adding a <symbol id="tb-yourname"> to _includes/icons.svg. Match the house style: a 24×24 stroke drawing, 1.75 width, round caps and joins, no fills — that consistency is what makes a row of them look like one set.


Certifications

{% include cert-wall.html %}
{% include cert-wall.html limit=4 %}
{% include cert.html cert=item quiet=true %}

Reads _data/certifications.yml. Featured entries come first with the accent seal; the rest go quiet — eight accent seals in a grid is eight things shouting, which is the same as none of them shouting.

The seal is a CSS clip-path, not an image, so it re-colours with your accent and there is nothing to re-export when the brand changes.


Collection lists

For a page that needs a grid somewhere other than at the end:

{% include collection-list.html items=site.projects style="deck" limit=3 %}

Styles: deck, numbered, bento, compact, rows. Renders an honest empty state when there is nothing in the collection.


Raw classes

Everything the theme draws is available as a class if a component does not fit. The full list is in _sass/trailblazer/, and the naming is consistent: tb-card, tb-card__body, tb-card--compact; utilities are tb-u-.

<div class="tb-grid-3">
  <article class="tb-card">
    <div class="tb-card__body">
      <p class="tb-card__meta">Meta</p>
      <h3 class="tb-card__title">Title</h3>
      <p class="tb-card__excerpt">Excerpt.</p>
    </div>
  </article>
</div>

Reach for a token before you reach for a rule — customising.md.

Found something wrong on this page? The source lives in docs/ — corrections welcome, see the contribution guide.

to move to open esc to close Full search