CKEditor 5 React integration provides cloud-based loading capabilities for dynamically importing CKEditor builds from CDN services, enabling reduced bundle sizes and flexible editor distribution.
React hook for loading CKEditor bundles from cloud/CDN services with async state management.
/**
* Hook for loading CKEditor bundles from cloud services
* Provides async state management for CDN-based editor loading
*/
function useCKEditorCloud<Config extends CKEditorCloudConfig>(
config: Config
): CKEditorCloudHookResult<Config>;
interface CKEditorCloudConfig {
/** CKEditor version to load */
version: string;
/** Array of language codes for translations */
translations?: string[];
/** Enable premium features */
premium?: boolean;
/** Additional plugins to load */
plugins?: string[];
/** CDN base URL override */
cdnUrl?: string;
}
type CKEditorCloudHookResult<Config extends CKEditorCloudConfig> =
| {
/** Loading state */
status: 'loading';
}
| {
/** Error state */
status: 'error';
error: any;
}
| ({
/** Success state with loaded CKEditor modules */
status: 'success';
} & CKEditorCloudResult<Config>);
interface CKEditorCloudResult<Config extends CKEditorCloudConfig> {
/** Core CKEditor modules */
CKEditor: {
ClassicEditor: typeof ClassicEditor;
InlineEditor: typeof InlineEditor;
BalloonEditor: typeof BalloonEditor;
DecoupledEditor: typeof DecoupledEditor;
MultiRootEditor: typeof MultiRootEditor;
[key: string]: any;
};
/** Premium features (if enabled) */
CKEditorPremiumFeatures?: {
[key: string]: any;
};
/** Additional plugins */
CKPlugins?: {
[key: string]: any;
};
}Usage Examples:
import React from 'react';
import { useCKEditorCloud, CKEditor } from '@ckeditor/ckeditor5-react';
// Basic cloud usage
function BasicCloudEditor() {
const cloud = useCKEditorCloud({
version: '42.0.0',
translations: ['es', 'de']
});
if (cloud.status === 'loading') {
return <div>Loading CKEditor from cloud...</div>;
}
if (cloud.status === 'error') {
return <div>Error loading CKEditor: {cloud.error?.message}</div>;
}
const { ClassicEditor } = cloud.CKEditor;
return (
<CKEditor
editor={ClassicEditor}
data="<p>Editor loaded from cloud!</p>"
onReady={(editor) => {
console.log('Cloud editor ready:', editor);
}}
/>
);
}
// Advanced cloud configuration
function AdvancedCloudEditor() {
const cloud = useCKEditorCloud({
version: '42.0.0',
translations: ['es', 'fr', 'de'],
premium: true,
plugins: ['CustomPlugin', 'SpecialFeature'],
cdnUrl: 'https://custom-cdn.example.com'
});
switch (cloud.status) {
case 'loading':
return (
<div>
<div>Loading CKEditor...</div>
<div>Version: 42.0.0</div>
<div>Premium features: enabled</div>
</div>
);
case 'error':
return (
<div style={{ color: 'red' }}>
<h3>Failed to load CKEditor</h3>
<p>Error: {cloud.error?.message}</p>
<p>Please check your network connection and try again.</p>
</div>
);
case 'success':
const { ClassicEditor, Bold, Italic, Link } = cloud.CKEditor;
const { PremiumPlugin } = cloud.CKEditorPremiumFeatures || {};
const { CustomPlugin } = cloud.CKPlugins || {};
return (
<div>
<h3>Cloud Editor Ready</h3>
<p>Loaded plugins: {Object.keys(cloud.CKEditor).length}</p>
<CKEditor
editor={ClassicEditor}
data="<p>Advanced cloud editor with premium features!</p>"
config={{
plugins: [Bold, Italic, Link, PremiumPlugin, CustomPlugin].filter(Boolean),
toolbar: ['bold', 'italic', 'link', 'premiumFeature']
}}
onReady={(editor) => {
console.log('Advanced cloud editor ready with plugins:',
editor.plugins.getPluginNames());
}}
/>
</div>
);
}
}
// Multi-language cloud editor
function MultiLanguageCloudEditor() {
const [currentLanguage, setCurrentLanguage] = useState('en');
const cloud = useCKEditorCloud({
version: '42.0.0',
translations: ['es', 'fr', 'de', 'pl']
});
if (cloud.status !== 'success') {
return <div>Loading editor...</div>;
}
const { ClassicEditor } = cloud.CKEditor;
return (
<div>
<div>
<label>Language: </label>
<select
value={currentLanguage}
onChange={(e) => setCurrentLanguage(e.target.value)}
>
<option value="en">English</option>
<option value="es">Español</option>
<option value="fr">Français</option>
<option value="de">Deutsch</option>
<option value="pl">Polski</option>
</select>
</div>
<CKEditor
key={currentLanguage} // Force re-render on language change
editor={ClassicEditor}
data="<p>Multi-language editor</p>"
config={{
language: currentLanguage,
toolbar: ['bold', 'italic', 'link']
}}
/>
</div>
);
}Higher-order component for injecting CKEditor cloud integration into components.
/**
* HOC for injecting CKEditor cloud integration into components
* Provides cloud loading state management and error handling
*/
function withCKEditorCloud<Config extends CKEditorCloudConfig>(
config: CKEditorCloudHocConfig<Config>
): <P extends object>(
WrappedComponent: ComponentType<WithCKEditorCloudHocProps<Config> & P>
) => ComponentType<Omit<P, keyof WithCKEditorCloudHocProps<Config>>>;
interface CKEditorCloudHocConfig<Config extends CKEditorCloudConfig> {
/** Cloud configuration */
cloud: Config;
/** Component to render while loading */
renderLoader?: () => ReactNode;
/** Component to render on error */
renderError?: (error: any) => ReactNode;
}
interface WithCKEditorCloudHocProps<Config extends CKEditorCloudConfig = CKEditorCloudConfig> {
/** Injected cloud result */
cloud: CKEditorCloudResult<Config>;
}HOC Usage Examples:
import React from 'react';
import { withCKEditorCloud, CKEditor } from '@ckeditor/ckeditor5-react';
// Basic HOC usage
const withCKCloud = withCKEditorCloud({
cloud: {
version: '42.0.0',
translations: ['es', 'de'],
premium: true
}
});
const MyEditorComponent = withCKCloud(({ cloud, title }) => {
const { ClassicEditor, Bold, Italic } = cloud.CKEditor;
const { PremiumFeature } = cloud.CKEditorPremiumFeatures || {};
return (
<div>
<h3>{title}</h3>
<CKEditor
editor={ClassicEditor}
data="<p>Editor with cloud integration via HOC</p>"
config={{
plugins: [Bold, Italic, PremiumFeature].filter(Boolean),
toolbar: ['bold', 'italic', 'premiumFeature']
}}
/>
</div>
);
});
// Usage
function App() {
return <MyEditorComponent title="My Cloud Editor" />;
}
// Advanced HOC with custom loading and error handling
const withAdvancedCKCloud = withCKEditorCloud({
cloud: {
version: '42.0.0',
premium: true
},
renderLoader: () => (
<div style={{ padding: '20px', textAlign: 'center' }}>
<div>🔄 Loading CKEditor...</div>
<div>Please wait while we fetch the editor from our CDN</div>
</div>
),
renderError: (error) => (
<div style={{ padding: '20px', color: 'red', border: '1px solid red' }}>
<h3>❌ CKEditor Load Failed</h3>
<p>Unable to load CKEditor from cloud service.</p>
<p>Error: {error?.message}</p>
<button onClick={() => window.location.reload()}>
Retry
</button>
</div>
)
});
const AdvancedCloudComponent = withAdvancedCKCloud(({ cloud, config }) => {
const { ClassicEditor } = cloud.CKEditor;
return (
<div>
<h3>Production Editor</h3>
<CKEditor
editor={ClassicEditor}
data="<p>Production-ready cloud editor</p>"
config={config}
onReady={(editor) => {
console.log('Production editor ready');
}}
/>
</div>
);
});
// Multiple editors with shared cloud HOC
const SharedCloudHOC = withCKEditorCloud({
cloud: {
version: '42.0.0',
translations: ['es', 'fr']
}
});
const MultiEditorComponent = SharedCloudHOC(({ cloud }) => {
const { ClassicEditor, InlineEditor } = cloud.CKEditor;
return (
<div>
<div>
<h4>Classic Editor</h4>
<CKEditor
editor={ClassicEditor}
data="<p>Classic editor content</p>"
/>
</div>
<div>
<h4>Inline Editor</h4>
<CKEditor
editor={InlineEditor}
data="<p>Inline editor content</p>"
/>
</div>
</div>
);
});Direct function for loading CKEditor from cloud services without React hooks.
/**
* Loads CKEditor bundles from cloud services
* Can be used outside of React components
*/
function loadCKEditorCloud<Config extends CKEditorCloudConfig>(
config: Config
): Promise<CKEditorCloudResult<Config>>;Direct Loading Usage:
import { loadCKEditorCloud } from '@ckeditor/ckeditor5-react';
// Preload CKEditor outside component
async function preloadCKEditor() {
try {
const cloudResult = await loadCKEditorCloud({
version: '42.0.0',
translations: ['es', 'fr'],
premium: true
});
console.log('CKEditor preloaded:', cloudResult);
// Store in global state or cache
window.preloadedCKEditor = cloudResult;
return cloudResult;
} catch (error) {
console.error('Failed to preload CKEditor:', error);
throw error;
}
}
// Use in application initialization
preloadCKEditor().then(() => {
console.log('CKEditor ready for use');
});
// Dynamic loading based on user preferences
async function loadEditorForUser(userPreferences) {
const config = {
version: '42.0.0',
translations: [userPreferences.language],
premium: userPreferences.hasPremium
};
try {
const cloudResult = await loadCKEditorCloud(config);
return cloudResult;
} catch (error) {
console.error('Failed to load personalized editor:', error);
// Fallback to basic configuration
return loadCKEditorCloud({ version: '42.0.0' });
}
}import React, { useState, useCallback } from 'react';
import { useCKEditorCloud, CKEditor } from '@ckeditor/ckeditor5-react';
function RobustCloudEditor() {
const [retryCount, setRetryCount] = useState(0);
const [forceReload, setForceReload] = useState(false);
const cloud = useCKEditorCloud({
version: '42.0.0',
premium: true,
// Add cache busting on retry
cdnUrl: forceReload ? `https://cdn.ckeditor.com?retry=${retryCount}` : undefined
});
const handleRetry = useCallback(() => {
setRetryCount(prev => prev + 1);
setForceReload(true);
setTimeout(() => setForceReload(false), 100);
}, []);
if (cloud.status === 'loading') {
return (
<div>
<div>Loading CKEditor from cloud...</div>
{retryCount > 0 && <div>Retry attempt: {retryCount}</div>}
</div>
);
}
if (cloud.status === 'error') {
return (
<div>
<h3>Failed to load CKEditor</h3>
<p>Error: {cloud.error?.message}</p>
<p>Attempts: {retryCount + 1}</p>
<button onClick={handleRetry}>
Retry Loading
</button>
{retryCount >= 3 && (
<div>
<p>Consider using a local build instead:</p>
<code>npm install ckeditor5</code>
</div>
)}
</div>
);
}
const { ClassicEditor } = cloud.CKEditor;
return (
<div>
<div>✅ CKEditor loaded successfully</div>
<CKEditor
editor={ClassicEditor}
data="<p>Cloud editor with error recovery</p>"
onError={(error, details) => {
console.error('Editor runtime error:', error);
if (!details.willEditorRestart) {
// Manual recovery might be needed
handleRetry();
}
}}
/>
</div>
);
}