Search Docs
Loading...
Skip to content

Photobook Editor for React

A complete photobook editor with a layouts library, photo auto-fill, live design validation, and export to print-ready PDF/X-4.

Photobook Editor starter kit showing a photobook spread with the layouts library and validation sidebar

15 mins
estimated time
Download
GitHub

Pre-requisites#

This guide assumes basic familiarity with React and TypeScript.

  • Node.js v22+ with npm – Download
  • Supported browsers – Chrome 114+, Edge 114+, Firefox 115+, Safari 15.6+
    See Browser Support for the full list

Get Started#

Start fresh with a standalone Photobook Editor project. This creates a complete, ready-to-run React application with a start screen, an editor, and an export pipeline.

Step 1: Create a New Project#

Terminal
npm create vite@latest your-project-name – –template react-ts
cd your-project-name
npm create vite@latest your-project-name – –template react-ts
cd your-project-name

Step 2: Copy the Editor Logic#

Copy the kit’s editor logic into the project you just created:

Terminal
npx degit imgly/starterkit-photobook-editor-react-web/src/client/src/imgly ./src/imgly
npx degit imgly/starterkit-photobook-editor-react-web/src/client/src/imgly ./src/imgly

Step 3: Install Dependencies#

Install the required packages for the editor:

Core Editor#

Install the Creative Editor SDK:

Terminal
npm install @cesdk/cesdk-js@1.83.0
npm install @cesdk/cesdk-js@1.83.0

Add the PDF/X conversion used by the export:

Terminal
npm install @imgly/plugin-print-ready-pdfs-web
npm install @imgly/plugin-print-ready-pdfs-web

Step 4: Download Assets#

CE.SDK requires engine assets (fonts, icons, UI elements) to function. These must be served as static files from your project’s public/ directory.

Terminal
curl -O https://cdn.img.ly/packages/imgly/cesdk-js/1.83.0/imgly-assets.zip
unzip imgly-assets.zip -d public/
rm imgly-assets.zip
curl -O https://cdn.img.ly/packages/imgly/cesdk-js/1.83.0/imgly-assets.zip
unzip imgly-assets.zip -d public/
rm imgly-assets.zip

Step 5: Create the Editor Component#

Create the editor and hand it to initPhotobookEditor with the scene to open:

src/PhotobookEditor.tsx
import CreativeEditor from '@cesdk/cesdk-js/react';
import { initPhotobookEditor } from './imgly';
export default function PhotobookEditor() {
return (
<CreativeEditor
config={{ userId: 'your-user-id', baseURL: '/assets' }}
init={(cesdk) =>
initPhotobookEditor(
cesdk,
'https://your-server.example.com/photobook-assets/style-playful-portrait.imgly'
)
}
width="100vw"
height="100vh"
/>
);
}

initPhotobookEditor takes a scene and nothing else. It configures the editor, loads the scene, and reads the rest — the page format and the asset root — from the scene itself.

Filling the book with photos is your app’s job, not the kit’s. See Set Up a Scene for the calls that do it.

Step 6: Use the Component#

Mount the editor in your app:

src/App.tsx
import PhotobookEditor from './PhotobookEditor';
export default function App() {
return <PhotobookEditor />;
}

What the Kit Offers#

  • Layouts — a layouts library filtered to the loaded page format. Applying one keeps the content already on the page.
  • Auto-fill — photos placed into the book automatically, each one matched to the slot that crops it least, and captions filled from your own copy.
  • Validation — a sidebar reporting low-resolution photos, empty slots, and content outside the trim, each one selectable.
  • PDF/X compliance — export to PDF/X-4 with a FOGRA39 output intent, the format commercial printers ask for.

Set Up a Scene#

A photobook starts from a template rather than an empty page. The kit opens the scene, then your app puts content into it:

src/client/src/app/App.tsx
// Any scene URL your asset bundle serves.
const sceneURL = `${DEMO_ASSETS_URL}/style-chic-portrait.imgly`;
await initPhotobookEditor(cesdk, sceneURL);
const photos = await addPhotosToUploadSource(
cesdk.engine,
examplePhotos,
uploadedFiles
);
// Skip both calls to let the reader place every photo by hand.
autoFillPhotobook(cesdk.engine, photos);
autoFillPhotobookTexts(cesdk.engine, exampleTexts);

In short: the scene decides the book, and filling it is your app’s job.

  • initPhotobookEditor takes only a scene and reads the format from it.
  • Adding a style means adding its scene to your asset bundle.
  • addPhotosToUploadSource is where your own photos come in.
  • Both auto-fill helpers touch only blocks the template marked as placeholders.
  • Size and style come from the start screen, configured in src/client/src/app/photobook-options.ts.

Customize#

Layouts#

The layouts library is a CE.SDK asset source. Choosing a layout re-lays out the current page instead of inserting a block, and switching to a layout with fewer slots does not discard photos — the extras move to a per-page stash and flow back when a larger layout returns.

Layouts are authored per page format. Each format has its own directory with its own content.json, scenes, and thumbnails:

layouts/
├── portrait/ # content.json, scenes/, thumbnails/
└── square/ # content.json, scenes/, thumbnails/

To add a layout, add its scene to your asset bundle and its entry to that format’s content.json:

layouts/portrait/content.json
{
"id": "portrait-001",
"label": { "en": "Title" },
"groups": ["Titles"],
"meta": {
"blockType": "acme.layouts",
"thumbUri": "{{base_url}}/portrait/thumbnails/portrait-001.png",
"uri": "{{base_url}}/portrait/scenes/portrait-001.blocks"
}
}

Authoring a Layout Scene#

A layout scene holds one page’s worth of slots, and the kit reads it as the page’s new content. Four rules make it behave once applied:

  1. One page per scene. The kit swaps the page’s children, so a scene with two pages contributes only the first.
  2. Mark every slot as a placeholder. Auto-fill, the layout stash, and the placeholderImage and placeholderText checks all key off the placeholder flag. A slot without it is never filled and never reported.
  3. Author at the format’s page size. Layouts live under the format directory whose pages they were drawn for; a scene drawn at another size arrives scaled.
  4. Give text slots their default copy. The placeholderText check compares the text against what the template shipped, so unedited captions are reported.

Photos reach the pages in the order given, but within a page auto-fill assigns them by shape, not position: it pairs the photos with the slots that crop them least. Slot geometry therefore decides which photo lands where.

Validation#

Validation runs against the book while the reader edits it and reports what would go wrong in print. Eight checks ship with the kit:

Check Fires when
outsidePage An element sits completely outside the page
protrudesFromPage An element extends beyond the page edge
lowResolution A photo is too small for its printed size
bleedMargin An element crosses the bleed margin
duplicateImage The same photo appears more than once
emptyPage A page has no content yet
placeholderImage An image slot has no photo yet
placeholderText Text still shows its placeholder content

The detectors live in src/client/src/imgly/validation.ts and report independently of any UI. Adding a check means adding its detector there, and a name and description for it wherever your interface presents the results — in this kit, src/client/src/app/validation-config.ts.

Export produces a PDF/X-4 file with a FOGRA39 output profile, set in PDFX_OPTIONS in src/client/src/app/print-ready-pdf.ts. The scene renders to a standard PDF first, then convertToPDFX from @imgly/plugin-print-ready-pdfs-web converts it.

Theming and Localization#

Match the editor to your brand by setting a theme in the editor configuration. See Theming for the full set of variables.

The kit’s own strings live in src/client/src/imgly/config/i18n.ts. Add a locale there alongside the editor’s built-in translations. See Localization.


Key Capabilities#

The Photobook Editor covers the path from a folder of photos to a file a printer accepts.

Layouts Library

Layouts Library

Swap a page between authored layouts. Photos and captions carry over, and extras wait in a stash until a larger layout takes them back.

Photo Auto-Fill

Photo Auto-Fill

Place uploaded photos into the book automatically, matching each photo to the slot whose shape crops it least.

Styled Templates

Styled Templates

Start every book from a real scene, authored per page format and style, instead of from a blank canvas.

Design Validation

Design Validation

Catch low-resolution photos, off-page content, and bleed-margin problems while the reader can still fix them.

Print-Ready Export

Print-Ready Export

Export PDF/X-4 with a FOGRA39 output intent, the format commercial printers ask for.

Multiple Book Formats

Multiple Book Formats

Offer portrait and square books at several sizes, each with its own layouts and its own style scenes.


Troubleshooting#

Editor doesn’t load#

  • Check the container element exists: Ensure your container element is in the DOM before calling create()
  • Verify the baseURL: Engine assets must be reachable from the CDN or your self-hosted location
  • Check console errors: Look for CORS or network errors in browser developer tools

Layouts or example photos don’t appear#

  • Check the demo asset location: The layouts, style scenes, and example photos come from a separate bundle. The kit derives their root from the scene URL you pass to initPhotobookEditor, so check that URL, or VITE_DEMO_ASSETS_BASE_URL when you run the kit as-is
  • Check network requests: Open the DevTools Network tab and look for failed requests to the asset host
  • Self-host assets for production: See Serve Assets to host assets on your infrastructure

Layouts don’t fill with photos#

  • Check the layout’s placeholders: Auto-fill only touches blocks the layout scene marked as placeholders. A layout authored without them stays empty. See Placeholders

Export is slow or blocks the editor#

  • Move rendering to the server: A large book competes with the editor for the main thread. Run the export server and set VITE_USE_SERVER=true
  • Wait for content to load: Ensure photos are fully loaded before exporting
  • Check CORS on images: Remote photos must allow cross-origin access

Watermark appears in production#

  • Add your license key: Set VITE_CESDK_LICENSE in your environment, or the license property in your configuration
  • Get a license: Contact us at img.ly/forms/contact-sales/

API Reference#

Most of what you need is four calls: open a scene, give it photos, fill it, and export it for print.

Call What it does
initPhotobookEditor(cesdk, sceneURL) Opens a photobook. Configures the editor, loads the scene, offers the layouts matching the scene’s page format, and locks the cover
addPhotosToUploadSource(engine, remotePhotos, files) Fills the upload source with the photos the book may use, and returns them for auto-fill
autoFillPhotobook(engine, photos) Fills every empty slot, matching each photo to the slot whose shape crops it least
toPrintReadyPDF(pdf, signal?) Converts an exported PDF to print-ready PDF/X-4. From src/client/src/app/print-ready-pdf.ts

Two more worth knowing:

  • VALIDATION_CHECKS in src/client/src/imgly/validation.ts — the print validation checks, each with the rule it applies. This is where you add a check of your own or drop one you do not want.
  • enterPreviewMode(cesdk, options) — switches the editor into the read-only page-spread preview and returns the function that exits it.

Everything else is exported from src/client/src/imgly/index.ts:

Export Kind What it does
initPhotobookEditor(cesdk, sceneURL) function Configures a CE.SDK instance for photobook editing: adds the editor configuration and asset source plugins, loads the scene, registers the layouts library for the format read from the loaded cover, stamps the template’s default texts, and locks the cover
DesignEditorConfig class The editor configuration plugin. Adds the actions, features, translations, settings, keyboard shortcuts, and UI layout. Add it with cesdk.addPlugin(new DesignEditorConfig())
UPLOAD_SOURCE_ID constant The id of the asset source the reader’s photos go into, ly.img.image.upload
revokeUploadedPhotoURLs() function Releases the object URLs created for uploaded files and drops their cached resolutions. Call it when the editor closes
PhotoRef type A photo available for filling the book: uri, width, height
RemotePhotoAsset type A remote example photo with known pixel dimensions, plus id, label, and thumbUri
autoFillPhotobook(engine, photos) function Fills every placeholder image slot in the book, matching each photo to the slot whose shape crops it least
autoFillPhotobookTexts(engine, texts) function Writes caption copy into the placeholder text blocks, page by page
PhotobookTextContent type The copy an auto-filled book is written with: { captions: string[] }
enterPreviewMode(cesdk, options) function Switches the editor into a read-only page-spread preview with its own navigation, and returns the function that exits it. Preview writes go into a scratch history, so the mode leaves no undo steps behind
LAYOUTS_SOURCE_ID constant The id of the layouts asset source, ly.img.layouts
LayoutsAssetSourcePlugin class Registers the layouts library for one page format. Applying a layout re-lays out the current page and carries its photos and text into the new slots
getLayoutFormat(size) function Returns the page format a size is authored at, portrait or square
getSceneLayoutFormat(engine) function Returns the page format of the loaded scene, read from its cover page
assetsBaseURLOf(sceneURL) function Returns the asset root a scene hangs off: its parent directory
addPhotosToUploadSource(engine, remotePhotos, files) function Adds photos to the upload source and returns them, the reader’s files first
getStyleSceneURL(assetsBaseURL, format, styleId) function Returns the scene URL a size and style combination starts from
PhotobookSize type A page format in millimeters: { width, height }
PhotobookStyleId type 'playful' | 'chic'
PhotoDistributionId type 'autoFill' | 'byHand'

Next Steps#