CKEditor 5 Autosave is a plugin that automatically saves editor content when changes occur. It provides configurable debouncing, integration with CKEditor 5's pending actions system, and support for both callback and adapter-based save implementations.
npm install ckeditor5 (this plugin is part of the main ckeditor5 package)import { Autosave } from '@ckeditor/ckeditor5-autosave';For type definitions:
import { Autosave, type AutosaveConfig, type AutosaveAdapter } from '@ckeditor/ckeditor5-autosave';import { ClassicEditor } from '@ckeditor/ckeditor5-editor-classic';
import { Autosave } from '@ckeditor/ckeditor5-autosave';
ClassicEditor
.create(document.querySelector('#editor'), {
plugins: [Autosave, /* other plugins */],
autosave: {
save(editor) {
// Must return a promise
return fetch('/save', {
method: 'POST',
body: JSON.stringify({ content: editor.getData() }),
headers: { 'Content-Type': 'application/json' }
});
},
waitingTime: 2000 // Wait 2 seconds after last change (default: 1000ms)
}
})
.then(editor => {
// Access autosave plugin
const autosave = editor.plugins.get('Autosave');
console.log(autosave.state); // 'synchronized', 'waiting', 'saving', or 'error'
});import { ClassicEditor } from '@ckeditor/ckeditor5-editor-classic';
import { Autosave, type AutosaveAdapter } from '@ckeditor/ckeditor5-autosave';
class CustomSaveAdapter implements AutosaveAdapter {
save(editor) {
return new Promise(resolve => {
// Custom save logic
localStorage.setItem('editor-content', editor.getData());
setTimeout(resolve, 100);
});
}
}
ClassicEditor
.create(document.querySelector('#editor'), {
plugins: [Autosave, /* other plugins */]
})
.then(editor => {
const autosave = editor.plugins.get('Autosave');
autosave.adapter = new CustomSaveAdapter();
});// Trigger manual save
await editor.plugins.get('Autosave').save();const autosave = editor.plugins.get('Autosave');
// Monitor save state changes
autosave.on('change:state', () => {
switch (autosave.state) {
case 'synchronized':
console.log('All changes saved');
break;
case 'waiting':
console.log('Waiting to save changes...');
break;
case 'saving':
console.log('Saving in progress...');
break;
case 'error':
console.log('Save failed, will retry...');
break;
}
});// Core CKEditor 5 types used by Autosave plugin
interface Editor {
readonly model: {
readonly document: ModelDocument;
};
readonly config: EditorConfig;
readonly plugins: PluginCollection;
getData(): string;
}
abstract class Plugin {
readonly editor: Editor;
constructor(editor: Editor);
init?(): void;
destroy?(): void;
}
interface PendingActions extends Plugin {
add(message: string): PendingAction;
remove(action: PendingAction): void;
}
interface PendingAction {
readonly message: string;
}
interface ModelDocument {
readonly version: number;
}
interface PluginCollection {
get<T extends Plugin>(plugin: string | { new(...args: any[]): T }): T;
}
interface EditorConfig {
get(configName: string): any;
autosave?: AutosaveConfig;
}The main plugin class that handles automatic saving of editor content.
class Autosave extends Plugin {
/** Plugin identifier */
static get pluginName(): 'Autosave';
/** Marks this as an official CKEditor plugin */
static get isOfficialPlugin(): true;
/** Required plugin dependencies */
static get requires(): [typeof PendingActions];
/** Custom save adapter instance */
adapter?: AutosaveAdapter;
/** Current plugin state - observable and readonly */
readonly state: 'synchronized' | 'waiting' | 'saving' | 'error';
/** Initialize the plugin */
constructor(editor: Editor);
/** Set up event listeners and start autosave functionality */
init(): void;
/** Clean up resources when plugin is destroyed */
destroy(): void;
/** Manually trigger a save operation */
save(): Promise<void>;
}Interface for implementing custom save adapters.
interface AutosaveAdapter {
/**
* Save method called when editor data changes
* @param editor - The editor instance containing the data to save
* @returns Promise that resolves when save operation completes
*/
save(editor: Editor): Promise<unknown>;
}Configuration options for the autosave feature.
interface AutosaveConfig {
/**
* Callback function executed when data needs to be saved.
* Must return a promise that resolves when save operation completes.
*/
save?(editor: Editor): Promise<unknown>;
/**
* Minimum time in milliseconds to wait after last change before saving.
* @default 1000
*/
waitingTime?: number;
}The Autosave plugin operates with the following behavior:
editor.model.document#change:data events to detect content changeswaitingTime (default 1000ms) to avoid excessive save callswindow#beforeunload events to save before page unloadsynchronized, waiting, saving, or errorThe plugin maintains four distinct states:
synchronized: All changes have been successfully savedwaiting: Plugin is waiting for the debounce period before initiating savesaving: Save operation is currently in progresserror: Save operation failed, plugin will automatically retryTo use the Autosave plugin:
Autosave to your editor's plugins configurationconfig.autosave.save or assign an adapter to the plugin instanceThe plugin extends the CKEditor 5 type system:
// Adds Autosave to the plugins map
declare module '@ckeditor/ckeditor5-core' {
interface PluginsMap {
Autosave: Autosave;
}
}