Inspired by the Inline spoilers plugin, this CSS snippet allows to create interactive hidden text:
This is achieved with HTML:
At the end of the book, <span class="spoiler" tabindex="0">everybody dies</span>
***
<b>What's the value of π?</b>
Answer: <span class="spoiler" tabindex="0">3.14159265358…</span>
CSS snippet
Inline_spoilers.css (840 Bytes)
/* Usage example: At the end of the movie, <span class="spoiler" tabindex="0">everybody dies</span> */
/* Source: https://forum.obsidian.md/t/inline-spoilers-with-css/104840 */
.spoiler {
background-color: var(--interactive-accent);
color: transparent;
padding: 0 3px;
border-radius: var(--radius-s);
cursor: pointer;
outline: none;
transition: all 0.2s ease;
}
.spoiler:focus {
background-color: hsla(var(--color-accent-hsl), 0.075);
color: var(--text-accent);
}
/* Fix for nested elements like links */
.spoiler > *,
.spoiler > *:hover {
color: transparent !important;
}
.spoiler:focus > *,
.spoiler:focus > *:hover {
color: var(--text-accent) !important;
}
/* Underline links */
.spoiler:focus a.internal-link,
.spoiler:focus a.external-link {
text-decoration: underline !important;
}
Templater script to wrap text in a spoiler:
Templater script
Toggle_Wrap_In_Spoiler.md (2.2 KB)
<%*
/**
* Template Name: Toggle Wrap in Spoiler
* Description: Wraps text in spoiler or removes it. Companion script to inline spoiler CSS snippet.
* Version: 1.0
* Last Updated: 2025-08-27
* Author: Created via Claude
* Source: https://forum.obsidian.md/t/inline-spoilers-with-css/104840
*/
const editor = app.workspace.activeEditor.editor;
const selections = editor.listSelections();
const selection = tp.file.selection();
const cursorStart = editor.getCursor('from');
// Check for multiple selections
if (selections.length > 1) {
new Notice("Multiple selections or cursors aren't supported");
tR = editor.getSelection();
return;
}
// Check if already wrapped in spoiler
const spoilerRegex = /^<span class="spoiler" tabindex="0">(.*?)<\/span>$/s;
if (!selection) {
// No selection - insert empty spoiler with cursor in middle
const openingTag = '<span class="spoiler" tabindex="0">';
const closingTag = '</span>';
tR = openingTag + closingTag;
setTimeout(() => {
editor.setCursor({
line: cursorStart.line,
ch: cursorStart.ch + openingTag.length
});
}, 0);
} else if (spoilerRegex.test(selection)) {
// Already wrapped - remove spoiler tags
const match = selection.match(spoilerRegex);
tR = match[1]; // Extract the content without spoiler tags
// Select the entire unwrapped text
setTimeout(() => {
const lines = tR.split('\n');
const lastLine = cursorStart.line + lines.length - 1;
const lastCh = lines[lines.length - 1].length;
editor.setSelection(
{line: cursorStart.line, ch: cursorStart.ch},
{line: lastLine, ch: cursorStart.ch + lastCh}
);
}, 0);
} else {
// Wrap selection in spoiler tags
tR = `<span class="spoiler" tabindex="0">${selection}</span>`;
// Select the entire wrapped text
setTimeout(() => {
const lines = tR.split('\n');
const lastLine = cursorStart.line + lines.length - 1;
const lastCh = lines[lines.length - 1].length;
editor.setSelection(
{line: cursorStart.line, ch: cursorStart.ch},
{line: lastLine, ch: cursorStart.ch + lastCh}
);
}, 0);
}
%>
The script also works as a toggle: if a selection is already wrapped in the span tag, the script will clear it.