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
- Debounce expensive operations like API calls
- Use onChange for auto-save rather than input events
- Prevent default for custom keyboard shortcuts
- Clean up listeners when destroying editors
- 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.
Marzipan