# Why customize the Sleekplan widget style
Sometimes the brand asks for one more tweak: a softer background, tighter typography, a sharper button. If you need to add CSS to iframe content, you can do it safely when the Sleekplan widget opens. This guide shows how to access iframe CSS at the right moment, inject a small style sheet, and keep it maintainable.
# Start with built‑in options
Before writing custom CSS, try the built-ins. In Settings, you can set brand color, light or dark theme, and launcher styles. It is fast, supports updates, and stays consistent across releases. If you still need custom rules, add them carefully and keep the surface small.
Tip: Review the features overview and defaults first. They cover most needs: Sleekplan features (opens new window).
# The approach: inject styles when the widget opens
The widget lives inside an iframe. You cannot style it from the parent until it is ready. The safe hook is the widget "open" event. On open, find the iframe, create a <style>
element, and append your CSS.
# Minimal snippet to add CSS to the iframe
<script>
// Run when the Sleekplan widget opens
window.$sleek.on('open', function() {
// 1) Your CSS. Keep it tight, target only what you must.
var cssContent = `
.app, .page { background-color: #f7fafc; }
* { font-size: 15px; }
`;
// 2) Find the iframe and inject a <style id=\"sleek-custom-style\">
var iframe = document.getElementById('sleek-widget');
if (!iframe || !iframe.contentDocument) return;
var iframeDoc = iframe.contentDocument;
var styleId = 'sleek-custom-style';
var styleEl = iframeDoc.getElementById(styleId) || iframeDoc.createElement('style');
styleEl.id = styleId;
styleEl.textContent = cssContent;
iframeDoc.head.appendChild(styleEl);
});
</script>
Key idea: inject on open, not on page load. The iframe must exist first.
# Production ready pattern
Make it robust: no duplicates, easy to update, and reversible when the widget closes.
<script>
(function() {
var STYLE_ID = 'sleek-custom-style';
function getIframeDoc() {
var iframe = document.getElementById('sleek-widget');
return iframe && iframe.contentDocument ? iframe.contentDocument : null;
}
function applyStyles(cssText) {
var doc = getIframeDoc();
if (!doc) return false;
var el = doc.getElementById(STYLE_ID) || doc.createElement('style');
el.id = STYLE_ID;
el.textContent = cssText;
if (!el.parentNode) doc.head.appendChild(el);
return true;
}
function removeStyles() {
var doc = getIframeDoc();
if (!doc) return;
var el = doc.getElementById(STYLE_ID);
if (el && el.parentNode) el.parentNode.removeChild(el);
}
var customCSS = `
/* Example tweaks */
.app { background: #ffffff; }
.button.primary { border-radius: 6px; }
.navbar .title { letter-spacing: 0.2px; }
`;
window.$sleek.on('open', function() {
applyStyles(customCSS);
});
// Optional: clean up on close
window.$sleek.on('close', function() {
removeStyles();
});
})();
</script>
Takeaway: treat styles as code. Add, update, and clean up deliberately.
# Targeting rules without breaking future updates
Classes inside the widget can evolve. Keep your selectors modest so updates do not break your overrides.
- Prefer low specificity selectors, for example: .app, .page, .button.primary
- Avoid star selectors for large areas, for example: * { font-size: 20px } influences everything
- Consider grouping to reduce overrides, for example: .app .content, .app .sidebar
- Use variables where available in your own CSS, not !important everywhere
Rule of thumb: the smaller your CSS surface, the fewer surprises later.
# Common style recipes
Try small, reversible changes first.
/* Typography */
.app { font-family: Inter, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
.app { line-height: 1.5; }
/* Colors */
.app { background-color: #f8fafc; }
.button.primary { background-color: #0ea5e9; color: #fff; }
/* Spacing */
.card { padding: 16px; }
.list .item { margin-bottom: 8px; }
/* Corners and borders */
.button, .input { border-radius: 6px; }
.input { border: 1px solid #d1d5db; }
Add the rules to the cssContent string in the injection snippet.
# Dark mode choices
If your app toggles dark mode, you can swap the injected CSS based on a class on
in your app.window.$sleek.on('open', function() {
var isDark = document.documentElement.classList.contains('dark');
var css = isDark ? `
.app { background:#0b1220; color:#e5e7eb; }
.card { background:#111827; }
` : `
.app { background:#ffffff; color:#111827; }
.card { background:#f9fafb; }
`;
// inject
var iframe = document.getElementById('sleek-widget');
if (!iframe || !iframe.contentDocument) return;
var doc = iframe.contentDocument;
var style = doc.getElementById('sleek-custom-style') || doc.createElement('style');
style.id = 'sleek-custom-style';
style.textContent = css;
doc.head.appendChild(style);
});
Small detail, big polish.
# Troubleshooting when you cannot access iframe CSS
If your script cannot add CSS to the iframe, check these basics.
- The widget is not open yet, make sure to listen to window.$sleek.on('open')
- The iframe id differs, confirm it is 'sleek-widget' in your DOM
- The iframe is not present due to ad or script blockers, test in a clean profile
- You replaced the widget DOM via hot reload, re-open the widget to re-inject
If you see errors in the console, re-check the order of events. The open hook solves most timing issues.
# FAQ: quick answers for featured snippets
How do I add CSS to an iframe for the Sleekplan widget? Listen to window.$sleek.on('open'), grab document.getElementById('sleek-widget').contentDocument, then append a
<style>
-element with your CSS.Can I access iframe CSS directly from the parent page? Not until the widget is opened and the iframe is ready. Inject a style tag on open, optionally remove it on close.
Is there a built-in field to paste custom CSS? No, use the open event to inject rules. For basics like colors and theme, use the built-in settings.
Will my overrides persist after widget updates? Keep selectors low specificity and minimal. Avoid deep internal selectors that may change.
# A closing note on craft
We choose the smallest change that does the job. That usually means one style element, a few clear selectors, and predictable events. Less to maintain, more control over the result.