This guide shows how to add save and export action buttons to your CE.SDK navigation bar using the Navigation Bar Order API.
Quick Start#
Add save and export buttons to your navigation bar:
import CreativeEditorSDK from '@cesdk/cesdk-js';
const cesdk = await CreativeEditorSDK.create(container, { license: 'YOUR_CESDK_LICENSE_KEY'});
// Add save and export buttonscesdk.ui.insertNavigationBarOrderComponent('last', { id: 'ly.img.actions.navigationBar', children: [ 'ly.img.saveScene.navigationBar', // Save scene 'ly.img.exportImage.navigationBar', // Export as image 'ly.img.exportPDF.navigationBar' // Export as PDF ]});
Save Button#
The save button (ly.img.saveScene.navigationBar
) persists the current scene state. You can use the default behavior or customize it.
Default Behavior#
// Adds a save button that downloads the scene filecesdk.ui.insertNavigationBarOrderComponent('last', { id: 'ly.img.actions.navigationBar', children: ['ly.img.saveScene.navigationBar']});
Custom Save with Notification#
// Register custom save callbackcesdk.actions.register('saveScene', async () => { const scene = await cesdk.engine.scene.saveToString(); await cesdk.utils.downloadFile(scene, 'text/plain;charset=UTF-8'); cesdk.ui.showNotification('Scene saved successfully');});
// Add save button that uses registered callbackcesdk.ui.insertNavigationBarOrderComponent('last', { id: 'ly.img.actions.navigationBar', children: ['ly.img.saveScene.navigationBar']});
Save to Backend#
// Register save callback that uploads to backendcesdk.actions.register('saveScene', async () => { const scene = await cesdk.engine.scene.saveToString();
try { console.log('Scene ready to save:', scene.length, 'characters');
// Production: // const { id } = await saveProjectToBackend(scene); // cesdk.ui.showNotification(`Saved (ID: ${id})`);
cesdk.ui.showNotification('Scene saved successfully'); } catch (error) { cesdk.ui.showNotification('Save failed', 'error'); }});
// Add save button that uses registered callbackcesdk.ui.insertNavigationBarOrderComponent('last', { id: 'ly.img.actions.navigationBar', children: ['ly.img.saveScene.navigationBar']});
Export Buttons#
Export buttons convert your design to different output formats. CE.SDK provides three default export buttons that all trigger the exportDesign
callback with different MIME types:
- Image Export (
ly.img.exportImage.navigationBar
) - passes{ mimeType: 'image/png' }
- PDF Export (
ly.img.exportPDF.navigationBar
) - passes{ mimeType: 'application/pdf' }
- Video Export (
ly.img.exportVideo.navigationBar
) - passes{ mimeType: 'video/mp4' }
The exportDesign
callback receives the export options including the MIME type, allowing you to handle different export formats appropriately.
Image Export#
The image export button (ly.img.exportImage.navigationBar
) exports the design as PNG.
Default Behavior (Download)#
Using just the string ID will download the exported PNG file to the user’s device:
// Default behavior: downloads PNG to user's devicecesdk.ui.insertNavigationBarOrderComponent('last', { id: 'ly.img.actions.navigationBar', children: ['ly.img.exportImage.navigationBar']});
Upload to CDN#
// Register export callback that uploads to CDNcesdk.actions.register('exportDesign', async (options) => { // The options will include { mimeType: 'image/png' } from the button const { blobs } = await cesdk.utils.export({ pngCompressionLevel: 7, ...options // This already contains mimeType: 'image/png' });
console.log('Image ready for upload:', blobs[0].size, 'bytes');
// Production: // const url = await uploadToCDN(blobs[0]);
cesdk.ui.showNotification('Image uploaded successfully');});
// Add export button that uses registered callbackcesdk.ui.insertNavigationBarOrderComponent('last', { id: 'ly.img.actions.navigationBar', children: ['ly.img.exportImage.navigationBar']});
PDF Export#
The PDF export button (ly.img.exportPDF.navigationBar
) exports all pages as a PDF.
Default Behavior (Download)#
Using just the string ID will download the PDF file to the user’s device:
// Default behavior: downloads PDF to user's devicecesdk.ui.insertNavigationBarOrderComponent('last', { id: 'ly.img.actions.navigationBar', children: ['ly.img.exportPDF.navigationBar']});
Upload to CDN#
// Register export callback that uploads PDFs to CDNcesdk.actions.register('exportDesign', async (options) => { // The options will include { mimeType: 'application/pdf' } from the button const { blobs } = await cesdk.utils.export({ targetDPI: 300, ...options // This already contains mimeType: 'application/pdf' });
console.log('PDF ready for upload:', blobs[0].size, 'bytes');
// Production: // const url = await uploadToCDN(blobs[0]);
cesdk.ui.showNotification('PDF uploaded successfully');});
// Add export button that uses registered callbackcesdk.ui.insertNavigationBarOrderComponent('last', { id: 'ly.img.actions.navigationBar', children: ['ly.img.exportPDF.navigationBar']});
Video Export#
The video export button (ly.img.exportVideo.navigationBar
) exports animations as MP4.
Default Behavior (Download)#
Using just the string ID will download the MP4 file to the user’s device:
// Default behavior: downloads MP4 to user's devicecesdk.ui.insertNavigationBarOrderComponent('last', { id: 'ly.img.actions.navigationBar', children: ['ly.img.exportVideo.navigationBar']});
Upload to CDN#
// Register video export callback that uploads to CDNcesdk.actions.register('exportDesign', async (options) => { // The options will include { mimeType: 'video/mp4' } from the button // Export video (utils.export handles its own loading dialog) const { blobs } = await cesdk.utils.export({ framerate: 30, ...options // This already contains mimeType: 'video/mp4' });
console.log('Video ready for upload:', blobs[0].size, 'bytes');
// Production: // const url = await uploadToCDN(blobs[0]);
cesdk.ui.showNotification('Video uploaded successfully');});
// Add export button that uses registered callbackcesdk.ui.insertNavigationBarOrderComponent('last', { id: 'ly.img.actions.navigationBar', children: ['ly.img.exportVideo.navigationBar']});
Handling Multiple Export Types#
Since all export buttons trigger the same exportDesign
callback with different MIME types, you can handle multiple export formats in a single callback:
// Register a unified export handler for all formatscesdk.actions.register('exportDesign', async (exportOptions) => { // The cesdk.utils.export automatically adapts based on the MIME type const { blobs, options } = await cesdk.utils.export(exportOptions);
// Handle different formats using the returned options if (options.mimeType?.startsWith('video/')) { console.log('Video ready:', blobs[0].size, 'bytes');
// Production: // await uploadVideoToCDN(blobs[0]);
cesdk.ui.showNotification('Video uploaded successfully'); } else if (options.mimeType === 'application/pdf') { console.log('PDF ready:', blobs[0].size, 'bytes');
// Production: // await uploadPDFToStorage(blobs[0]);
cesdk.ui.showNotification('PDF saved to storage'); } else { console.log('Image ready:', blobs[0].size, 'bytes');
// Production: // await uploadImageToCDN(blobs[0]);
cesdk.ui.showNotification('Image uploaded successfully'); }});
// Add all export buttons - they'll all use the same callbackcesdk.ui.insertNavigationBarOrderComponent('last', { id: 'ly.img.actions.navigationBar', children: [ 'ly.img.exportImage.navigationBar', // Passes { mimeType: 'image/png' } 'ly.img.exportPDF.navigationBar', // Passes { mimeType: 'application/pdf' } 'ly.img.exportVideo.navigationBar' // Passes { mimeType: 'video/mp4' } ]});
Custom Export with Loading Dialogs#
When using the engine APIs directly instead of cesdk.utils.export
, you need to:
- Create your own loading dialog using
cesdk.utils.showLoadingDialog
- Handle the export type detection yourself based on the MIME type
- Manage progress updates manually
Complete Custom Export Implementation#
Use the engine API directly when you need fine-grained control over the export process. This example shows how to handle all export types (image, PDF, video) using only engine APIs:
// Register custom export using only engine APIs for full controlcesdk.actions.register('exportDesign', async (options) => { // Create loading dialog for all export types const dialogController = cesdk.utils.showLoadingDialog({ title: 'Exporting', message: 'Processing your design...', progress: 'indeterminate', abortLabel: 'Cancel', onAbort: () => console.log('Export cancelled') });
try { const page = cesdk.engine.scene.getCurrentPage(); if (page === null) { throw new Error('No page selected for export'); }
let blob;
// Handle different export types with engine APIs if (options?.mimeType?.startsWith('video/')) { // Video export with progress blob = await cesdk.engine.block.exportVideo(page, { mimeType: options.mimeType, targetWidth: 1920, targetHeight: 1080, framerate: 30, onProgress: (rendered, encoded, total) => { dialogController.updateProgress({ value: rendered, max: total }); } }); } else { // Static export (image, PDF) blob = await cesdk.engine.block.export(page, { mimeType: options?.mimeType || 'image/png', pngCompressionLevel: 7, targetWidth: 1920, targetHeight: 1080 }); }
console.log('Export ready:', blob.size, 'bytes');
// Production: // const url = await uploadToCDN(blob); // await navigator.clipboard.writeText(url);
// Show success dialogController.showSuccess({ message: 'Export successful' });
} catch (error) { // Show error dialogController.showError({ message: 'Export failed. Please try again.' }); }});
// Add export button that uses registered callbackcesdk.ui.insertNavigationBarOrderComponent('last', { id: 'ly.img.actions.navigationBar', children: ['ly.img.exportImage.navigationBar']});
Related Resources#
- Navigation Bar Order API - Complete navigation customization guide
- Actions API - File operations and dialogs
- Export Formats - Supported export formats and options