Novel reader snippets
How custom CSS and JavaScript snippets behave in the Novel WebView reader:
- Where snippets are applied
- Which rules win when multiple styles/scripts exist
Before you start
Snippets are intended for the WebView novel renderer.
- Open a novel chapter.
- Open reader settings.
- Set rendering mode to WebView.
- Go to Advanced and use the CSS/JS snippet sections.
If you use the TextView renderer, WebView snippets do not run.
This is a function of the native android TextView, and will not be changed.
Execution order
For a normal chapter load, the order is:
- Chapter preprocessing (native Kotlin):
- Hide chapter title option
- Force lowercase option
- Translation option
- Content sanitization:
- Strips chapter-inline
<script>,<style>, and<noscript>blocks - Media stripping option
- Applies enabled Regex Find/Replace rules
- Strips chapter-inline
- EPUB extraction (if enabled):
- If
Enable EPUB CSSis on,<style data-epub-css>is moved into the document<head> - If
Enable EPUB JSis on,<script data-epub-js>is moved into the document<head>
- If
- Initial HTML is loaded into WebView (with base style + extracted EPUB head content +
window.__TSUNDOKU_*variables). - After page finished (
onPageFinished) the app injects in this order:- Reader settings CSS/JS
- EPUB JS/CSS
- Custom CSS
- Custom JS
User CSS/JS runs after base content load, and after EPUB head content is attached.
CSS priority and merge order
The injected style text is assembled in this order:
- generated base style (font size, line height, margins, colors, text selection, paragraph spacing, etc.)
- enabled CSS snippets (in list order)
Because CSS is appended in that order, later rules override earlier ones when specificity is equal.
JavaScript behavior and order
The runtime JS layers are:
- During initial HTML build, the app writes
window.__TSUNDOKU_*variables:__TSUNDOKU_CHAPTER_TITLE__TSUNDOKU_CHAPTER_NUMBER__TSUNDOKU_CHAPTER_URL__TSUNDOKU_NOVEL_URL__TSUNDOKU_IS_EDIT_MODE__TSUNDOKU_IS_INF_SCROLL__TSUNDOKU_TEXT_SELECTION_BLOCKED__TSUNDOKU_FORCED_LOWERCASE
- After page finishes loading, object
window.Tsundokuis created:chapterTitle,chapterNumber,chapterUrl,novelUrlisEditMode,isInfScroll,textSelectionBlocked,forcedLowercase
If you need more variables exposed to JS, open an issue with your use case or submit a PR.
EPUB CSS/JS options
The reader has EPUB toggles in Advanced:
- Enable EPUB CSS
- Enable EPUB JS
These toggle whether EPUB-embedded blocks marked as data-epub-css and data-epub-js are kept and injected into <head>.
Js run order:
For JS and CSS, Reader settings load first, then EPUB, then user code
Safe snippet practices
- Keep snippets small and focused.
- Prefer id/class selectors scoped to chapter content.
- Avoid heavy loops/mutation observers without guards.
- Guard against missing nodes:
const target = document.querySelector('.chapter-content');
if (target) {
// your logic
}- If your code has loops, guard against infinite loops.
- For CSS, prefer scoped selectors over
*when possible.
Troubleshooting
Snippet seems ignored
- Confirm renderer is WebView.
- Ensure snippet is Enabled.
- Check for selector mismatch on current source HTML (Textview mode has a raw html option).
- Temporarily disable other snippets to detect override conflicts.
Style conflict
- Move conflicting rule to a later snippet or combine into one snippet.
- Some elements like body might have
!importantapplied on some of the styles. Apply!importanton your style if it doesn't work. This overrides other CSS elements, which can get the desired result if you know it takes priority!