image

08 Apr 2026

ConfluenceAtlassianHTMLJavaScriptCSSProductivity

5 Things You Can Build with HTML Macro for Confluence

Confluence is a solid documentation platform. But the moment you need a colored status badge, a countdown to your launch date, or a table that users can actually sort — you hit a wall. Native macros only go so far.

HTML Macro for Confluence fills that gap. It lets you drop a full HTML/CSS/JS editor directly into any Confluence page. Live preview, CSP security controls, granular access permissions — and it runs entirely on Atlassian Forge with nothing sent to external servers.

Here are five concrete things teams are building with it right now.


1. Custom Status Badge / Traffic Light Indicator

The problem: Your project status page needs a RAG (Red/Amber/Green) indicator that's quick to read and easy for editors to update. The native Confluence status macro is limited, and color-coded text doesn't stand out enough for at-a-glance checks.

The solution: A simple HTML/CSS badge with a colored circle and a label. Editors change one word to flip the status.

<!-- HTML -->
<div class="rag-badge">
  <span class="dot green"></span>
  <span class="label">On Track</span>
</div>
/* CSS */
.rag-badge {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: sans-serif;
  font-size: 16px;
  font-weight: 600;
}

.dot {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
}

.dot.green  { background-color: #22c55e; box-shadow: 0 0 8px #22c55e88; }
.dot.amber  { background-color: #f59e0b; box-shadow: 0 0 8px #f59e0b88; }
.dot.red    { background-color: #ef4444; box-shadow: 0 0 8px #ef444488; }

.label { color: #1e293b; }

Why it's useful: Swap greenamberred on the dot class and update the label text. That's the entire update. No Confluence macros to reconfigure, no separate status apps to install. Engineers, PMs, and project leads can glance at a page and immediately know where things stand.


2. Embedded Countdown Timer

The problem: Your team has a product launch date, a sprint end, or a compliance deadline coming up. A static date in the page body gets ignored. Teams want something that actively reminds them how much runway is left.

The solution: A JavaScript countdown that calculates days, hours, and minutes remaining from a target date, updating every second.

<!-- HTML -->
<div class="countdown-wrapper">
  <div class="countdown-title">Launch Countdown</div>
  <div class="countdown-timer">
    <div class="unit"><span id="days">--</span><label>Days</label></div>
    <div class="unit"><span id="hours">--</span><label>Hours</label></div>
    <div class="unit"><span id="minutes">--</span><label>Minutes</label></div>
  </div>
</div>
/* CSS */
.countdown-wrapper { font-family: sans-serif; text-align: center; padding: 24px; background: #f8fafc; border-radius: 12px; }
.countdown-title { font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em; color: #64748b; margin-bottom: 16px; }
.countdown-timer { display: flex; justify-content: center; gap: 24px; }
.unit { display: flex; flex-direction: column; align-items: center; }
.unit span { font-size: 48px; font-weight: 700; color: #1e293b; line-height: 1; }
.unit label { font-size: 12px; color: #94a3b8; margin-top: 4px; text-transform: uppercase; letter-spacing: 0.06em; }
// JavaScript — set your target date here
const target = new Date("2026-05-01T09:00:00");

function tick() {
  const diff = target - new Date();
  if (diff <= 0) {
    document.querySelector(".countdown-timer").innerHTML = "<p>We're live!</p>";
    return;
  }
  document.getElementById("days").textContent    = Math.floor(diff / 86400000);
  document.getElementById("hours").textContent   = Math.floor((diff % 86400000) / 3600000);
  document.getElementById("minutes").textContent = Math.floor((diff % 3600000) / 60000);
}

tick();
setInterval(tick, 1000);

Why it's useful: Change one date string and you have a live countdown that works for any milestone. Sprint reviews, feature freezes, go-live dates — it's a passive but effective nudge every time someone opens the page.


3. Interactive Decision Tree for Runbooks

The problem: Runbooks and incident response guides are often long, linear documents. Engineers in the middle of an incident don't want to read paragraphs — they want to answer a question and be told exactly what to do next.

The solution: A clickable HTML/CSS decision tree that walks users through branching logic step by step. No external charting library required.

<!-- HTML -->
<div class="tree" id="tree">
  <div class="node active" id="q1">
    <p>Is the service returning errors?</p>
    <div class="choices">
      <button onclick="show('q1-yes')">Yes</button>
      <button onclick="show('q1-no')">No</button>
    </div>
  </div>
  <div class="node" id="q1-yes">
    <p>Are errors 5xx (server-side)?</p>
    <div class="choices">
      <button onclick="show('check-logs')">Yes</button>
      <button onclick="show('check-upstream')">No</button>
    </div>
  </div>
  <div class="node answer" id="check-logs">
    <p>Check application logs in Datadog. Look for OOM errors or unhandled exceptions. Page the on-call engineer if needed.</p>
    <button onclick="reset()">Start over</button>
  </div>
  <div class="node answer" id="check-upstream">
    <p>Likely a 4xx or gateway issue. Check upstream dependencies and API gateway logs.</p>
    <button onclick="reset()">Start over</button>
  </div>
  <div class="node answer" id="q1-no">
    <p>Service appears healthy. Check monitoring dashboards for latency spikes or queue depth issues.</p>
    <button onclick="reset()">Start over</button>
  </div>
</div>
/* CSS */
.tree { font-family: sans-serif; max-width: 480px; }
.node { display: none; padding: 20px; border: 1px solid #e2e8f0; border-radius: 10px; margin-bottom: 12px; background: #fff; }
.node.active { display: block; }
.node p { margin: 0 0 14px; font-size: 15px; color: #1e293b; font-weight: 500; }
.choices { display: flex; gap: 10px; }
button { padding: 8px 18px; border: none; border-radius: 6px; background: #6366f1; color: #fff; font-size: 14px; cursor: pointer; }
button:hover { background: #4f46e5; }
.answer { background: #f0fdf4; border-color: #86efac; }
.answer p { color: #166534; font-weight: 400; }
.answer button { background: #64748b; }
// JavaScript
function show(id) {
  document.querySelectorAll(".node").forEach(n => n.classList.remove("active"));
  document.getElementById(id).classList.add("active");
}
function reset() { show("q1"); }

Why it's useful: Runbook authors can build arbitrarily deep trees using just HTML — no Mermaid, no Lucidchart license needed. The tree lives inside the Confluence page, is searchable, and can be updated by anyone with access to the macro editor.


4. Custom Data Table with Sort and Filter

The problem: Confluence tables are static. You can't click a column header to sort, and there's no filter input. For any table with more than a dozen rows — vendor lists, feature matrices, environment configs — this is a real usability problem.

The solution: A vanilla JavaScript snippet that adds click-to-sort to any HTML table, plus a live filter input.

<!-- HTML -->
<div class="table-wrapper">
  <input id="filter" type="text" placeholder="Filter rows..." />
  <table id="data-table">
    <thead>
      <tr>
        <th>Service</th>
        <th>Owner</th>
        <th>Status</th>
        <th>SLA</th>
      </tr>
    </thead>
    <tbody>
      <tr><td>Auth API</td><td>Platform</td><td>Healthy</td><td>99.9%</td></tr>
      <tr><td>Billing</td><td>Payments</td><td>Degraded</td><td>99.5%</td></tr>
      <tr><td>Notifications</td><td>Growth</td><td>Healthy</td><td>99.0%</td></tr>
      <tr><td>Search</td><td>Platform</td><td>Healthy</td><td>99.9%</td></tr>
      <tr><td>Analytics</td><td>Data</td><td>Maintenance</td><td>98.0%</td></tr>
    </tbody>
  </table>
</div>
/* CSS */
.table-wrapper { font-family: sans-serif; }
#filter { width: 100%; padding: 8px 12px; margin-bottom: 12px; border: 1px solid #cbd5e1; border-radius: 6px; font-size: 14px; box-sizing: border-box; }
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th { background: #f1f5f9; padding: 10px 14px; text-align: left; cursor: pointer; user-select: none; border-bottom: 2px solid #e2e8f0; color: #475569; }
th:hover { background: #e2e8f0; }
td { padding: 10px 14px; border-bottom: 1px solid #f1f5f9; color: #1e293b; }
tr:hover td { background: #f8fafc; }
th.asc::after  { content: " ▲"; font-size: 11px; }
th.desc::after { content: " ▼"; font-size: 11px; }
// JavaScript
const table = document.getElementById("data-table");
const tbody = table.querySelector("tbody");
const headers = table.querySelectorAll("th");
let sortCol = -1, sortAsc = true;

headers.forEach((th, i) => {
  th.addEventListener("click", () => {
    if (sortCol === i) { sortAsc = !sortAsc; } else { sortCol = i; sortAsc = true; }
    headers.forEach(h => h.classList.remove("asc", "desc"));
    th.classList.add(sortAsc ? "asc" : "desc");
    const rows = Array.from(tbody.querySelectorAll("tr"));
    rows.sort((a, b) => {
      const av = a.cells[i].textContent.trim();
      const bv = b.cells[i].textContent.trim();
      return sortAsc ? av.localeCompare(bv) : bv.localeCompare(av);
    });
    rows.forEach(r => tbody.appendChild(r));
  });
});

document.getElementById("filter").addEventListener("input", function () {
  const q = this.value.toLowerCase();
  tbody.querySelectorAll("tr").forEach(row => {
    row.style.display = row.textContent.toLowerCase().includes(q) ? "" : "none";
  });
});

Why it's useful: Replace the <tbody> rows with your actual data and you have a fully sortable, filterable table with zero dependencies. Works for service registries, on-call rosters, feature flags, release checklists — anything that lives in a Confluence table but deserves better UX.


5. Branded Announcement Banner

The problem: HR needs to announce open enrollment. Marketing wants to flag a product launch to all readers of a space. The built-in Confluence info panel is functional but bland — it doesn't match company branding and blends into the page noise.

The solution: A CSS-styled announcement banner with a company-colored left border, an icon, a headline, and body text. Completely customizable.

<!-- HTML -->
<div class="announcement">
  <div class="announcement-icon">📣</div>
  <div class="announcement-body">
    <div class="announcement-title">Open Enrollment — Action Required</div>
    <div class="announcement-message">
      Benefits enrollment is open until <strong>April 30, 2026</strong>.
      Log in to Workday and complete your selections before the deadline.
      Contact <a href="mailto:[email protected]">[email protected]</a> with questions.
    </div>
  </div>
</div>
/* CSS */
.announcement {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  padding: 18px 20px;
  border-left: 5px solid #6366f1;
  background: #eef2ff;
  border-radius: 0 10px 10px 0;
  font-family: sans-serif;
  max-width: 680px;
}

.announcement-icon {
  font-size: 24px;
  flex-shrink: 0;
  margin-top: 2px;
}

.announcement-title {
  font-size: 15px;
  font-weight: 700;
  color: #3730a3;
  margin-bottom: 6px;
}

.announcement-message {
  font-size: 14px;
  color: #1e293b;
  line-height: 1.6;
}

.announcement-message a {
  color: #6366f1;
  text-decoration: none;
  font-weight: 500;
}

.announcement-message a:hover { text-decoration: underline; }

Why it's useful: Change the border color and background tint to match your brand palette, swap in your own headline and message, and you have a polished callout that actually gets noticed. No graphic design skills needed, and the same template works for IT alerts, policy updates, and event announcements.


A Note on Security

Embedding HTML and JavaScript in a documentation platform is a responsibility that admins need to control. HTML Macro for Confluence gives you three Content Security Policy modes:

  • Block All — the strictest setting. No external resources (scripts, fonts, images) can load. This is the right default for pure HTML/CSS snippets like the badge and banner examples above.
  • Whitelist — you specify exactly which external domains are permitted. If your team uses Chart.js from a CDN or embeds a Google Map, you add those domains to the allowlist and nothing else gets through.
  • Allow All — fully permissive. Appropriate for tightly controlled internal environments where you trust every editor.

Combined with editor access control — which limits who can open the code editor in the first place — you can let most teams use the rendered output without ever exposing the source code.


Try It Free

All five of the examples above work today, without any paid tier, without any external server, and without leaving Confluence.

HTML Macro for Confluence is free on the Atlassian Marketplace. Install it, drop it into a page, and paste in one of the snippets above to see the live preview update as you type.

Install HTML Macro for Confluence — free on the Atlassian Marketplace


Have a use case we didn't cover? We'd love to hear what your team builds. Reach out through our support portal.

Featured App

HTML Macro

Embed custom HTML, CSS, and JavaScript directly inside Confluence pages

Stay in the loop

Get product updates and tips straight to your inbox.

No spam, ever.

Related Articles

View all →
Embed Custom HTML, CSS & JavaScript in Confluence — Introducing HTML Macro for Confluence
02 Apr 2026

Embed Custom HTML, CSS & JavaScript in Confluence — Introducing HTML Macro for Confluence

HTML Macro for Confluence is now live on the Atlassian Marketplace! Embed interactive widgets, branded layouts, and custom code directly inside Confluence pages — with live preview and enterprise-grade security.

Read more
Confluence vs Notion for Engineering Teams: An Honest Comparison
31 Mar 2026

Confluence vs Notion for Engineering Teams: An Honest Comparison

Notion is sleek. Confluence is powerful. But which one actually works better for engineering teams? Here's an honest breakdown covering docs, code, integrations, and scale.

Read more
How to Export Confluence to Markdown (Complete Guide)
28 Mar 2026

How to Export Confluence to Markdown (Complete Guide)

Need your Confluence docs in markdown? Here's how to export a single page, a page tree, or an entire space — with attachments, hierarchy, and formatting intact.

Read more