Sleekplan’s Website settings in the admin dashboard include three powerful customization fields: Custom HTML, Custom CSS, and Custom JavaScript. These let you tailor the standalone version of your feedback site without changing the core product. You can inject small enhancements (like styling tweaks), or richer behavior (like dynamic menus) to improve navigation, highlight key content, and better match your brand. For example, you might have a numerous categories for incoming feedback.
In this guide, we’ll use the Custom JavaScript field to add a collapsible “Categories” menu to the sidebar.
⚡Follow the steps below to add a collapsible categories drop-down using Custom JavaScript:
2. Paste the following JavaScript snippet into the Custom JavaScript field and Save it.
🔔 The code snippet contains a section for CSS styling. You can adapt it to your own styling requirements if needed.
(function () {
var SECTION_SELECTOR = '.section.filter.filter-feedback .overflow-navigation';
var WRAPPER_CLASS = 'sp-collapsible-wrapper';
var TOGGLE_CLASS = 'sp-collapsible-toggle';
var CONTENT_CLASS = 'sp-collapsible-content';
var STYLE_ID = 'sp-collapsible-styles';
var INIT_ATTR = 'data-sp-collapsible-initialized';
var STORAGE_KEY = 'sp-categories-open';
function injectStyles() {
if (document.getElementById(STYLE_ID)) return;
var style = document.createElement('style');
style.id = STYLE_ID;
style.textContent =
'.' + WRAPPER_CLASS + '{display:block}' +
'.' + TOGGLE_CLASS + '{' +
' display:flex;align-items:center;justify-content:space-between;' +
' width:100%;cursor:pointer;background:transparent;border:0;padding:8px 4px;' +
' color:inherit;font:inherit;text-align:left;' +
'}' +
'.' + TOGGLE_CLASS + ' .label{font-weight:600}' +
'.' + TOGGLE_CLASS + ' .chev{transition:transform .2s ease;display:inline-block;margin-left:8px}' +
'.' + CONTENT_CLASS + '{' +
' overflow:hidden;transition:max-height .25s ease;' +
'}' +
// spacing so the list looks like the original
'.' + CONTENT_CLASS + ' .navigation-item{display:flex;align-items:center;padding:6px 4px}' +
'.' + CONTENT_CLASS + ' .navigation-item .colored{margin-right:8px}';
document.head.appendChild(style);
}
function createToggle(labelText) {
var btn = document.createElement('button');
btn.type = 'button';
btn.className = TOGGLE_CLASS;
btn.setAttribute('aria-expanded', 'false');
var label = document.createElement('span');
label.className = 'label';
label.textContent = labelText || 'Categories';
var chev = document.createElement('span');
chev.className = 'chev';
chev.setAttribute('aria-hidden', 'true');
// use ▸ closed, rotate to ▾ when open
chev.textContent = '▸';
btn.appendChild(label);
btn.appendChild(chev);
return btn;
}
function measureOpenHeight(el) {
// Temporarily set max-height to none to read full height
var prev = el.style.maxHeight;
el.style.maxHeight = 'none';
var h = el.scrollHeight;
el.style.maxHeight = prev || '0px';
return h;
}
function setOpenState(btn, content, open) {
btn.setAttribute('aria-expanded', open ? 'true' : 'false');
var chev = btn.querySelector('.chev');
if (chev) chev.style.transform = open ? 'rotate(90deg)' : 'rotate(0deg)';
if (open) {
var h = measureOpenHeight(content);
content.style.maxHeight = h + 'px';
} else {
content.style.maxHeight = '0px';
}
try { localStorage.setItem(STORAGE_KEY, open ? '1' : '0'); } catch (e) {}
}
function bindToggle(btn, content) {
if (btn._spBound) return;
btn._spBound = true;
btn.addEventListener('click', function () {
var isOpen = btn.getAttribute('aria-expanded') === 'true';
setOpenState(btn, content, !isOpen);
});
// Adjust max-height on resize (so it matches content if open)
window.addEventListener('resize', function () {
if (btn.getAttribute('aria-expanded') === 'true') {
content.style.maxHeight = measureOpenHeight(content) + 'px';
}
});
}
function buildOnce(container) {
if (!container || container.getAttribute(INIT_ATTR) === '1') return;
// Collect current category links (direct children <a.navigation-item>)
var links = Array.prototype.slice.call(container.querySelectorAll(':scope > a.navigation-item'));
if (links.length === 0) return; // nothing to do
// Create wrapper + toggle + content
var wrapper = document.createElement('div');
wrapper.className = WRAPPER_CLASS;
var toggle = createToggle('Categories');
var content = document.createElement('div');
content.className = CONTENT_CLASS;
content.style.maxHeight = '0px';
// Move links into content
links.forEach(function (a) { content.appendChild(a); });
// Insert into DOM
wrapper.appendChild(toggle);
wrapper.appendChild(content);
container.appendChild(wrapper);
// Initial open/closed from localStorage (default closed)
var open = false;
try { open = localStorage.getItem(STORAGE_KEY) === '1'; } catch (e) {}
setOpenState(toggle, content, open);
bindToggle(toggle, content);
container.setAttribute(INIT_ATTR, '1');
}
function init() {
injectStyles();
var container = document.querySelector(SECTION_SELECTOR);
if (container) buildOnce(container);
}
// Run when DOM ready or immediately if ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
// Observe re-renders and re-init if the section changes
var mo = new MutationObserver(function () {
var container = document.querySelector(SECTION_SELECTOR);
if (!container) return;
// If Sleekplan rebuilt the section, our INIT_ATTR might be missing
if (!container.getAttribute || container.getAttribute(INIT_ATTR) !== '1') {
init();
} else {
// ensure button has handler and styles applied
var btn = container.querySelector('.' + TOGGLE_CLASS);
var content = container.querySelector('.' + CONTENT_CLASS);
if (btn && content) bindToggle(btn, content);
}
});
mo.observe(document.documentElement, { childList: true, subtree: true });
})();
🪧 After saving, reload your feedback site to see the collapsible “Categories” toggle. If you want the dropdown to default open, change the “open” variable in buildOnce to true, or remove the localStorage logic that remembers the state.
🚩 Custom scripts can only be applied to websites with a custom domain. Find out how to Connect a Custom Domain.


