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