Skip to content
On this page

Events & Callbacks

Learn how to respond to editor events and user interactions.

Content Events

onChange

Called whenever content changes:

ts
new Marzipan('#editor', {
  onChange: (value, instance) => {
    console.log('New content:', value);
    console.log('Instance ID:', instance.instanceId);
    
    // Auto-save
    localStorage.setItem('content', value);
  }
});

Input Monitoring

Access the textarea directly for native events:

ts
const [editor] = new Marzipan('#editor');

editor.textarea.addEventListener('input', (e) => {
  console.log('Input event:', e);
});

editor.textarea.addEventListener('paste', (e) => {
  console.log('Paste event:', e);
});

Focus Events

ts
const [editor] = new Marzipan('#editor');

editor.textarea.addEventListener('focus', () => {
  console.log('Editor focused');
});

editor.textarea.addEventListener('blur', () => {
  console.log('Editor blurred');
});

Keyboard Events

onKeydown Callback

ts
new Marzipan('#editor', {
  onKeydown: (event, instance) => {
    // Ctrl/Cmd + S to save
    if ((event.ctrlKey || event.metaKey) && event.key === 's') {
      event.preventDefault();
      saveContent(instance.getValue());
    }
    
    // Ctrl/Cmd + P to print
    if ((event.ctrlKey || event.metaKey) && event.key === 'p') {
      event.preventDefault();
      printContent(instance.getValue());
    }
  }
});

Direct Event Listeners

ts
const [editor] = new Marzipan('#editor');

editor.textarea.addEventListener('keydown', (e) => {
  // Tab to insert spaces
  if (e.key === 'Tab') {
    e.preventDefault();
    document.execCommand('insertText', false, '  ');
  }
});

Selection Events

ts
const [editor] = new Marzipan('#editor');

editor.textarea.addEventListener('selectionchange', () => {
  const start = editor.textarea.selectionStart;
  const end = editor.textarea.selectionEnd;
  console.log(`Selection: ${start}-${end}`);
});

Toolbar Events

ts
const [editor] = new Marzipan('#editor', { toolbar: true });

// Toolbar buttons trigger standard events
editor.container.addEventListener('click', (e) => {
  const button = e.target.closest('button');
  if (button) {
    console.log('Toolbar button clicked:', button.dataset.action);
  }
});

Custom Events

Dispatch custom events from your code:

ts
const [editor] = new Marzipan('#editor', {
  onChange: (value, instance) => {
    // Dispatch custom event
    const event = new CustomEvent('markdown:changed', {
      detail: { value, wordCount: value.split(/\s+/).length }
    });
    instance.element.dispatchEvent(event);
  }
});

// Listen for custom events
editor.element.addEventListener('markdown:changed', (e) => {
  console.log('Word count:', e.detail.wordCount);
});

Debounced Events

ts
let timeout;
new Marzipan('#editor', {
  onChange: (value, instance) => {
    // Debounce saves
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      saveToServer(value);
    }, 1000);
  }
});

Advanced: Stats Updates

ts
const [editor] = new Marzipan('#editor', { showStats: true });

// Monitor stats changes
const observer = new MutationObserver(() => {
  const statsBar = editor.container.querySelector('.marzipan-stats');
  if (statsBar) {
    console.log('Stats updated:', statsBar.textContent);
  }
});

observer.observe(editor.container, {
  subtree: true,
  characterData: true
});

Best Practices

  1. Debounce expensive operations like API calls
  2. Use onChange for auto-save rather than input events
  3. Prevent default for custom keyboard shortcuts
  4. Clean up listeners when destroying editors
  5. Use event delegation for toolbar customization

Complete Example

ts
const [editor] = new Marzipan('#editor', {
  toolbar: true,
  showStats: true,
  
  onChange: (value, instance) => {
    // Debounced auto-save
    clearTimeout(this.saveTimer);
    this.saveTimer = setTimeout(() => {
      localStorage.setItem('draft', value);
      showNotification('Draft saved');
    }, 1000);
  },
  
  onKeydown: (event, instance) => {
    // Custom shortcuts
    if (event.ctrlKey || event.metaKey) {
      if (event.key === 's') {
        event.preventDefault();
        publishContent(instance.getValue());
      }
      if (event.key === 'p') {
        event.preventDefault();
        previewContent(instance.getValue());
      }
    }
  }
});

// Focus events
editor.textarea.addEventListener('focus', () => {
  document.body.classList.add('editor-focused');
});

editor.textarea.addEventListener('blur', () => {
  document.body.classList.remove('editor-focused');
});

For more details, see the API Reference.

Released under the Apache 2.0 License