One of the missing features in standard Wiki.js installations is the ability to create collapsible "accordion" sections for long documentation pages. While there are plugins, sometimes you just want a lightweight, code-injection solution that works with your existing Markdown.
I recently built a solution that turns standard Markdown headers (H2, H3, H4) into interactive, collapsible sections.
grid-template-rows CSS trick for smooth height transitions without JavaScript height calculations.+ / - indicators.The script runs a bottom-up scan of your headers (H6 -> H2). For every header found, it grabs all following sibling elements until it hits a header of the same or higher level. It wraps these elements in a div.
Because it processes H3s before H2s, the H3 wrappers end up inside the H2 wrappers, creating a perfect nested structure automatically.
Animating height: auto is notoriously difficult in CSS. Instead of using JavaScript to calculate pixel heights, we use a CSS Grid wrapper:
.wiki-collapsible-wrapper {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.3s ease-out;
}
.wiki-collapsible-wrapper.active {
grid-template-rows: 1fr;
}
This allows the browser to handle the interpolation perfectly smoothly.
Go to your Wiki.js Administration panel (Gear Icon next to your profile picture.) -> Theme
In the CSS Override text box:
/* 1. The Grid Wrapper */
.wiki-collapsible-wrapper {
display: grid;
grid-template-rows: 0fr;
opacity: 0;
transition: grid-template-rows 0.3s ease-out, opacity 0.3s ease-out;
background-color: transparent;
}
.wiki-collapsible-wrapper.active {
grid-template-rows: 1fr;
opacity: 1;
}
/* 2. The Inner Container */
.wiki-collapsible-inner {
overflow: hidden;
padding: 0 18px;
}
/* 3. The Header Styling */
.wiki-collapsible-header {
cursor: pointer;
user-select: none;
display: flex;
align-items: center;
justify-content: space-between;
background-color: #eee;
color: #444;
padding: 10px 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
margin-top: 10px;
margin-bottom: 0;
border-radius: 4px;
}
.wiki-collapsible-header:hover,
.wiki-collapsible-header.active {
background-color: #ccc;
}
/* The Symbol (+ / -) */
.wiki-collapsible-header::after {
content: '\002B';
color: #777;
font-weight: bold;
float: right;
margin-left: 15px;
font-size: 1rem;
}
.wiki-collapsible-header.active::after {
content: "\2212";
}
/* Reset margins for headers that become buttons */
.markdown-body h2.wiki-collapsible-header,
.markdown-body h3.wiki-collapsible-header,
.markdown-body h4.wiki-collapsible-header {
margin-bottom: 0;
line-height: 1.5;
}
In the Body HTML Injection text box:
<script>
document.addEventListener("DOMContentLoaded", function() {
// 1. Check for Opt-In Flag
const isEnabled = document.querySelector('.wiki-collapsible-enable');
if (!isEnabled) return;
// 2. Select Container
const container = document.querySelector('.wiki-content') || document.querySelector('.markdown-body') || document.body;
// 3. Process Headers (Bottom-Up)
const headers = ['h6', 'h5', 'h4', 'h3', 'h2'];
headers.forEach(tagName => {
const elements = Array.from(container.querySelectorAll(tagName));
elements.forEach(header => {
const wrapper = document.createElement('div');
wrapper.className = 'wiki-collapsible-wrapper';
const inner = document.createElement('div');
inner.className = 'wiki-collapsible-inner';
const currentLevel = parseInt(tagName.substring(1));
let nextNode = header.nextElementSibling;
const nodesToWrap = [];
while (nextNode) {
const nextTagName = nextNode.tagName ? nextNode.tagName.toLowerCase() : '';
if (/^h[1-6]$/.test(nextTagName)) {
const nextLevel = parseInt(nextTagName.substring(1));
if (nextLevel <= currentLevel) {
break;
}
}
nodesToWrap.push(nextNode);
nextNode = nextNode.nextElementSibling;
}
if (nodesToWrap.length > 0) {
nodesToWrap.forEach(node => inner.appendChild(node));
wrapper.appendChild(inner);
header.parentNode.insertBefore(wrapper, header.nextElementSibling);
header.classList.add('wiki-collapsible-header');
header.addEventListener('click', function() {
this.classList.toggle("active");
wrapper.classList.toggle("active");
});
}
});
});
});
</script>
To enable this on a specific page, edit the page, click the page settings option at the top of the editor,
<span class="wiki-collapsible-enable" style="display:none;"></span>
That's it! Your static Markdown headers are now interactive accordions.