Visual Indicators for Draft and Future Posts in Jekyll
· 9 min readMy previous article on Jekyll Run plugin configuration documented a frustrating problem: when you run jekyll serve --drafts --future, draft and future-dated posts appear in your listings but look identical to published posts. You can’t tell at a glance which articles are live on production and which are still waiting.
After scrolling past 130+ posts trying to spot my drafts one too many times, I added visual indicators — a pencil icon for drafts, a robot icon for future-dated posts (because robots are cool and futuristic), and italic text for both. The indicators only appear during local development because drafts and future posts don’t exist in production builds. Making system state visible at a glance is a UX principle that applies equally to monitoring dashboards, CI/CD pipelines, and content management — if you have to dig to find the status, the status isn’t working.
| Drafts | Future |
|---|---|
| (PENCIL) | (ROBOT) |
The Problem
Running jekyll serve --drafts --future --unpublished renders everything into site.posts. The archive page, home page, and paginated listings all show drafts and future posts mixed in with published content. There’s no visual distinction.
This matters when you have 50 drafts and 5 future-dated posts queued up. You want to:
- Quickly identify what’s live vs what’s scheduled
- Spot drafts that accidentally have
published: true(they’ll deploy if moved to_posts/) - Verify that future-dated posts have the correct dates before they go live
What Jekyll Exposes
Before building anything, I needed to confirm what data Jekyll makes available in templates.
Future posts are straightforward. Every post has a post.date, and Jekyll provides site.time (the build timestamp). Compare them:
{% if post.date > site.time %}
<!-- this post is future-dated -->
{% endif %}
Drafts are trickier. Jekyll doesn’t set a post.draft flag or expose the source collection. But drafts come from the _drafts/ directory, and that path is available:
{% if post.path contains '_drafts/' %}
<!-- this post is a draft -->
{% endif %}
This works because post.path contains the relative path from the site root, including the directory name.
In production, neither check matters — drafts and future posts aren’t in site.posts at all when building without --drafts and --future. The conditionals are inert. No performance cost, no risk of leaking unpublished content.
The Implementation
Adding Icons to the SVG Sprite
This blog uses a Font Awesome SVG sprite that’s built at compile time from icons referenced in _config.yml. Only icons listed under navigation and external get included. To add the draft and future icons without polluting those lists, I added a new config key:
# _config.yml
post_status_icons:
- {icon: pencil-alt} # draft posts
- {icon: robot} # future-dated posts
And extended the sprite template to include them:
<!-- assets/fontawesome/icons.svg -->
{% assign keys = 'navigation,external,post_status_icons' | split: ',' %}
{% for key in keys %}
{% for link in site[key] %}
{% assign icon = link.icon %}
{% assign svg = site.data.font-awesome.icons[icon].svg | first %}
<symbol id="{{ icon }}" viewBox="0 0 {{ svg[1].width }} {{ svg[1].height }}">
<path d="{{ svg[1].path }}" />
</symbol>
{% endfor %}
{% endfor %}
This adds exactly two SVG symbols to the sprite — no CDN load, no external requests.
Archive Page
The _includes/archive.html gets the detection logic and conditional rendering:
{% for post in site.posts %}
{%- assign is_draft = false -%}
{%- assign is_future = false -%}
{%- if post.path contains '_drafts/' -%}{%- assign is_draft = true -%}{%- endif -%}
{%- if post.date > site.time -%}{%- assign is_future = true -%}{%- endif -%}
<li>
<time datetime="{{ post.date | date_to_xmlschema }}">{{ post.date | date: "%Y-%m-%d" }}</time>
{%- if is_draft %}
<svg aria-label="Draft" class="icon icon-status" title="Draft">
<use xlink:href="{{ "/assets/fontawesome/icons.svg" | relative_url }}#pencil-alt"></use>
</svg>
{%- elsif is_future %}
<svg aria-label="Future" class="icon icon-status" title="Scheduled">
<use xlink:href="{{ "/assets/fontawesome/icons.svg" | relative_url }}#robot"></use>
</svg>
{%- endif %}
{%- if is_draft or is_future %}
<em><a href="{{ post.url | relative_url }}">{{ post.title }}</a></em>
{%- else %}
<a href="{{ post.url | relative_url }}">{{ post.title }}</a>
{%- endif %}
</li>
{% endfor %}
Draft entries get a pencil icon. Future entries get a robot icon. Both get italic text. Published posts render normally with no extra markup.
Here’s what future-dated posts look like in the archive with the robot icon and italic styling:
And drafts with the pencil icon:
Home Page Excerpt Views
The _includes/meta.html header component passes the detection through as include parameters:
{% include meta.html post=post preview=true is_draft=is_draft is_future=is_future %}
Inside meta.html, the icon renders next to the post title:
<h1>
<a href="{{ include.post.url | relative_url }}">{{ include.post.title }}</a>
{%- if include.is_draft %}
<svg aria-label="Draft" class="icon icon-status" title="Draft">
<use xlink:href="{{ "/assets/fontawesome/icons.svg" | relative_url }}#pencil-alt"></use>
</svg>
{%- elsif include.is_future %}
<svg aria-label="Future" class="icon icon-status" title="Scheduled">
<use xlink:href="{{ "/assets/fontawesome/icons.svg" | relative_url }}#robot"></use>
</svg>
{%- endif %}
</h1>
The excerpt <article> wrapper also gets a class for italic styling:
<article{% if is_draft or is_future %} class="post-preview-unpublished"{% endif %}>
CSS
Two additions to _sass/classes.sass:
.icon-status
height: .85em
width: .85em
opacity: .6
margin: 0 .2em
.post-preview-unpublished
font-style: italic
The status icons are slightly smaller and more transparent than navigation icons — they’re informational, not interactive. The italic class applies to the entire excerpt card for draft and future posts.
Files Changed
| File | Change |
|---|---|
_config.yml |
Added post_status_icons with pencil-alt and robot |
assets/fontawesome/icons.svg |
Extended sprite loop to include post_status_icons |
_includes/archive.html |
Draft/future detection with icons and italics |
_includes/home.html |
Same treatment for paginated excerpt view |
_includes/meta.html |
Icon badge next to post title in headers |
_layouts/home.html |
Same treatment for list-style home layout |
_layouts/paginate.html |
Same treatment for paginate layout |
_layouts/archive.html |
Same treatment for archive layout |
_sass/classes.sass |
Added .icon-status and .post-preview-unpublished |
Why These Icons
Pencil (pencil-alt) for drafts — universally understood as “editing” or “work in progress.” It’s already in Font Awesome Free and visually distinct at small sizes.
Robot for future posts — a nod to the automated scheduled publishing via GitHub Actions cron. The daily build at 00:05 UTC is the “robot” that publishes future-dated posts when their date arrives. It’s also visually distinctive and unlikely to be confused with any other status.
I considered clock and hourglass for future posts but they’re too generic — they could mean “reading time” or “loading.” The robot is unambiguous in context.
Production Safety
This feature is inherently safe for production:
- No
--draftsflag → no drafts insite.posts→ no pencil icons rendered - No
--futureflag → no future posts insite.posts→ no robot icons rendered - The Liquid conditionals evaluate to false and produce zero HTML output
- The SVG sprite includes the two extra icon symbols (~2KB), but they’re never referenced in production HTML
The only “cost” in production is two unused <symbol> elements in the SVG sprite file. They add negligible bytes and are never rendered by the browser.
Related Posts
- Jekyll Run Plugin: Local Development Settings That Actually Work — The predecessor article on configuring
--draftsand--futureflags - How the Sausage Is Made: Every Feature Powering This Jekyll Blog — Complete feature reference
- Building This Blog: Jekyll on GitHub Pages from Zero to 130+ Posts — Blog setup guide
- The CI/CD Pipeline Behind This Jekyll Blog — How scheduled builds publish future-dated posts
References
- Jekyll Drafts Documentation — Official docs on the
_draftsfolder - Jekyll Configuration: Show Drafts — CLI flags for draft and future rendering
- Font Awesome Free Icons — Icon browser

