Use Case

    Documentation & Knowledge-Base Editor

    Build a knowledge-base authoring experience with Scribe: headings via heading(n), code blocks, internal links via link(url), localStorage autosave on onChange, and clean HTML via getHTML().

    heading(n)
    Document structure
    onChange
    localStorage autosave
    getHTML()
    Clean KB output

    Everything a docs editor needs

    Headings & document structure

    Call editor.heading(2) and editor.heading(3) to build a clean H1–H6 hierarchy — the backbone of any documentation page and its on-page table of contents.

    Code blocks & inline code

    Technical docs need code. Scribe supports inline code and code blocks, and getHTML() emits clean semantic markup you can syntax-highlight on render.

    Autosave to localStorage

    Wire onChange to a debounced save into localStorage so writers never lose a draft. Restore it with setHTML() on load, and clear it once it's committed to the server.

    Internal links & clean output

    Use editor.link("/docs/api-reference") for internal KB cross-links. getHTML() returns clean, XSS-sanitized HTML safe to store and re-render across your knowledge base.

    Docs Editor with Headings & Internal Links

    Use heading(n) for structure and link(url) for internal KB cross-links, then publish via getHTML().

    import { Scribe } from 'scribejs-editor';
    import 'scribejs-editor/dist/scribe.css';
    
    // A docs editor wants a fixed toolbar for long-form structured writing
    const editor = Scribe.init('#doc-body', {
      toolbar:     'fixed',
      autofocus:   true,
      placeholder: 'Write your documentation...',
      onChange:    (html) => autosaveLocal(html),
    });
    
    // Headings for structure, code blocks, and internal links
    document.querySelector('#h2').addEventListener('click', () => editor.heading(2));
    document.querySelector('#h3').addEventListener('click', () => editor.heading(3));
    
    // Internal link to another KB article
    document.querySelector('#internal-link').addEventListener('click', () => {
      const slug = prompt('Article slug (e.g. /docs/api-reference):');
      if (slug) editor.link(slug);
    });
    
    // Publish clean HTML to your knowledge base
    document.querySelector('#publish').addEventListener('click', async () => {
      const html = editor.getHTML();   // clean semantic HTML, safe to store
      await fetch(`/api/kb/${articleId}`, {
        method:  'PUT',
        headers: { 'Content-Type': 'application/json' },
        body:    JSON.stringify({ content: html }),
      });
    });

    Autosave with onChange + localStorage

    Wire onChange to a debounced write into localStorage, then restore the draft with setHTML() on load.

    import { Scribe } from 'scribejs-editor';
    
    const STORAGE_KEY = `kb-draft-${articleId}`;
    
    const editor = Scribe.init('#doc-body', {
      toolbar:  'fixed',
      onChange: scheduleAutosave,
    });
    
    // Restore an unsaved local draft on load (localStorage source of truth)
    const cached = localStorage.getItem(STORAGE_KEY);
    if (cached) editor.setHTML(cached);
    
    // Debounced autosave to localStorage so writers never lose work
    let saveTimer;
    function scheduleAutosave(html) {
      clearTimeout(saveTimer);
      document.querySelector('#status').textContent = 'Saving...';
      saveTimer = setTimeout(() => {
        localStorage.setItem(STORAGE_KEY, html);
        document.querySelector('#status').textContent = 'Saved locally';
      }, 1500);
    }
    
    // Clear the local draft once it is committed to the server
    async function publish() {
      const html = editor.getHTML();
      await fetch(`/api/kb/${articleId}`, {
        method:  'PUT',
        headers: { 'Content-Type': 'application/json' },
        body:    JSON.stringify({ content: html }),
      });
      localStorage.removeItem(STORAGE_KEY);
    }

    React Documentation Editor Component

    A complete React component with localStorage autosave, draft restore, and publish.

    import { useRef, useEffect, useState, useCallback } from 'react';
    import { Scribe } from 'scribejs-editor';
    
    export function DocsEditor({ articleId, initialContent }) {
      const containerRef = useRef(null);
      const editorRef    = useRef(null);
      const saveTimer    = useRef(null);
      const [status, setStatus] = useState('');
      const storageKey = `kb-draft-${articleId}`;
    
      useEffect(() => {
        editorRef.current = Scribe.init(containerRef.current, {
          toolbar:     'fixed',
          autofocus:   true,
          placeholder: 'Write your documentation...',
          onChange:    scheduleAutosave,
        });
        // Prefer a local draft, fall back to the server content
        const cached = localStorage.getItem(storageKey);
        editorRef.current.setHTML(cached ?? initialContent ?? '');
        return () => editorRef.current?.destroy();
      }, [articleId]);
    
      const scheduleAutosave = useCallback((html) => {
        clearTimeout(saveTimer.current);
        setStatus('Saving...');
        saveTimer.current = setTimeout(() => {
          localStorage.setItem(storageKey, html);
          setStatus('Saved locally');
        }, 1500);
      }, [storageKey]);
    
      const publish = async () => {
        const html = editorRef.current?.getHTML();
        if (!html) return;
        await fetch(`/api/kb/${articleId}`, {
          method:  'PUT',
          headers: { 'Content-Type': 'application/json' },
          body:    JSON.stringify({ content: html }),
        });
        localStorage.removeItem(storageKey);
        setStatus('Published');
      };
    
      return (
        <div className="docs-editor">
          <div className="docs-toolbar">
            <span className="status">{status}</span>
            <button onClick={publish}>Publish</button>
          </div>
          <div ref={containerRef} className="prose prose-lg max-w-none" />
        </div>
      );
    }

    Everything a docs author expects

    Headings H1–H6 via heading(n)
    Inline code & code blocks
    Ordered & unordered lists
    Blockquote callouts
    Internal links via link(url)
    onChange autosave to localStorage
    setHTML() to restore drafts
    getHTML() for clean KB output
    Built-in XSS sanitization
    Paste clean from Word & Google Docs
    Zero dependencies, under 50KB
    MIT-licensed, React/Vue/Svelte/Vanilla

    Ship your documentation editor today.

    Headings, code blocks, internal links, autosave, clean HTML. Everything in 50KB — free under MIT.

    Documentation & KB editor — common questions

    How do I build a documentation editor in JavaScript?

    Initialize Scribe Editor with toolbar: 'fixed' for long-form writing, use editor.heading(n) for structure, support code blocks and inline code, and use editor.link('/docs/...') for internal cross-links. On publish, call editor.getHTML() to get clean semantic HTML. Scribe is under 50KB gzipped, MIT-licensed, and works with React, Vue 3, Svelte, and Vanilla JS.

    How do I add autosave with localStorage to a docs editor?

    In the Scribe onChange callback, clear a previous timeout and set a new one (around 1.5 seconds). When it fires, write editor.getHTML() to localStorage under a per-article key. On load, restore the draft with editor.setHTML(cached). Remove the localStorage key once the article is committed to the server so the local draft doesn't override published content.

    Can Scribe Editor handle headings and code blocks for documentation?

    Yes. Use editor.heading(2) through editor.heading(6) to build a heading hierarchy, plus inline code and code blocks for technical content. getHTML() emits clean semantic HTML, so you can apply your own syntax highlighting and table-of-contents generation when rendering the published article.

    Does Scribe produce clean HTML safe to store in a knowledge base?

    Yes. editor.getHTML() returns clean, semantic HTML with built-in XSS sanitization, and paste handling strips proprietary Word and Google Docs markup. That means the documentation HTML you store stays consistent and safe to re-render across your knowledge base.