SeatSquirrel
DeploymentSelf-Hosted Mode

Designer API Reference

Complete API reference for the SeatSquirrel Designer

Constructor Options

new SeatSquirrel.Designer(options)

Shared Callbacks (Both Modes)

These options work in both standalone and iframe SDK modes.

OptionTypeRequiredDescription
permissionsDesignerPermissionsNoRestrict which features are enabled in the designer. Default: all features enabled.
onReady() => voidNoCalled when designer is ready.
onLayoutLoaded() => voidNoCalled when loadLayout() succeeds. Pure confirmation signal — no payload.
onSave(data: { layout: LayoutOutput }) => voidNoCalled when user clicks Save.
onLayoutChanged(data: { hasChanges: boolean }) => voidNoCalled when unsaved changes status changes.
onPricingCategoriesChanged(data: { hasChanges: boolean }) => voidNoCalled when pricing changes; call getPricingCategories() for data.
onError(error: { message: string, code: string, details?: string }) => voidNoCalled when an error occurs.

iFrame SDK Only

These options only apply when using the iframe SDK. They are not available in standalone mode.

OptionTypeRequiredDescription
containerstring | HTMLElementYesCSS selector or DOM element for the iframe
baseUrlstringNoLocation of the SeatSquirrel app (default: https://seatsquirrel.com)
designerUrlstringNoFull URL override for the designer page. Takes precedence over baseUrl. Useful for servers requiring .html extensions (e.g., https://example.com/designer.html)

Restricting Designer Features

Use the permissions option to control which tools and features are available in the designer.

Disable pricing category management

When you supply pricing categories from your external system, you typically want to prevent users from creating or modifying them:

Standalone mode (window.SeatSquirrelConfig):

window.SeatSquirrelConfig = {
  permissions: {
    properties: {
      pricingCategoriesCrud: false,
      currencySettings: false
    }
  },
  onReady: function () {
    SeatSquirrel.designer.setPricingCategories({
      mode: 'replace',
      pricingCategories: [
        { id: 'vip', label: 'VIP', slug: 'vip', price: 15000, color: '#8b5cf6' },
        { id: 'standard', label: 'Standard', slug: 'standard', price: 5000, color: '#3b82f6' }
      ]
    });
  },
  onSave: function (layout) {
    console.log('Layout saved:', layout);
  }
};

iFrame SDK mode (new SeatSquirrel.Designer()):

const designer = new SeatSquirrel.Designer({
  container: '#designer',
  permissions: {
    properties: {
      pricingCategoriesCrud: false,
      currencySettings: false
    }
  },
  onReady: () => {
    designer.setPricingCategories({
      mode: 'replace',
      pricingCategories: [
        { id: 'vip', label: 'VIP', slug: 'vip', price: 15000, color: '#8b5cf6' },
        { id: 'standard', label: 'Standard', slug: 'standard', price: 5000, color: '#3b82f6' }
      ]
    });
  }
});

Read-only preview mode

// Standalone
window.SeatSquirrelConfig = {
  permissions: { readOnly: true }
};

// iFrame SDK
const designer = new SeatSquirrel.Designer({
  container: '#designer',
  permissions: { readOnly: true }
});

Assignment-only mode

Allows pricing category assignment while blocking all structural and visual edits:

  • Pricing category assignment remains enabled
  • Creating, moving, resizing, and deleting objects is disabled
  • Undo/redo, copy/paste, and destructive controls are hidden
  • Settings tab and category CRUD are disabled
  • Save and export remain available
  • Selected elements show greyed-out (non-editable) properties below the pricing editor
  • If both readOnly and assignmentOnly are true, readOnly takes precedence
// Standalone
window.SeatSquirrelConfig = {
  permissions: { assignmentOnly: true }
};

// iFrame SDK
const designer = new SeatSquirrel.Designer({
  container: '#designer',
  permissions: { assignmentOnly: true }
});

// Hide greyed-out properties (restore previous behavior)
window.SeatSquirrelConfig = {
  permissions: {
    assignmentOnly: true,
    properties: { showProperties: false }
  }
};

Limit available tools

// Only allow rows and areas (hide tables, shapes, text tools)

// Standalone
window.SeatSquirrelConfig = {
  permissions: {
    tools: {
      table: false,
      shape: false,
      text: false,
      traceImage: false
    }
  }
};

// iFrame SDK
const designer = new SeatSquirrel.Designer({
  container: '#designer',
  permissions: {
    tools: {
      table: false,
      shape: false,
      text: false,
      traceImage: false
    }
  }
});

Hide the Settings tab

// Standalone
window.SeatSquirrelConfig = {
  permissions: {
    properties: {
      settingsTab: false
    }
  }
};

// iFrame SDK
const designer = new SeatSquirrel.Designer({
  container: '#designer',
  permissions: {
    properties: {
      settingsTab: false
    }
  }
});

Suppress pricing category save warning

When pricing is managed externally and you don't want users to see warnings about missing pricing categories on save:

// Standalone
window.SeatSquirrelConfig = {
  permissions: {
    warnings: {
      pricingCategoriesAssignmentSaveWarning: false
    }
  }
};

// iFrame SDK
const designer = new SeatSquirrel.Designer({
  container: '#designer',
  permissions: {
    warnings: {
      pricingCategoriesAssignmentSaveWarning: false
    }
  }
});

Suppress pricing category panel warning

Hide the amber "Missing Pricing Categories" warning box shown in the properties panel when nothing is selected:

// Standalone
window.SeatSquirrelConfig = {
  permissions: {
    warnings: {
      pricingCategoriesAssignmentPanelWarning: false
    }
  }
};

// iFrame SDK
const designer = new SeatSquirrel.Designer({
  container: '#designer',
  permissions: {
    warnings: {
      pricingCategoriesAssignmentPanelWarning: false
    }
  }
});

Methods

Summary

MethodParametersReturns
loadLayout(layoutData)layoutData: LayoutOutputStandalone: { success: boolean }
iFrame: Promise<{ success: boolean }>
getLayout({ mode }){ mode: 'current' | 'last-saved' }Standalone: { layout: LayoutOutput | null }
iFrame: Promise<{ layout: LayoutOutput | null }>
hasChanges(){ hasChanges: boolean }
setPermissions(permissions)DesignerPermissions{ success: boolean }
clearLayout(){ success: boolean }
setPricingCategories({ mode, ... }){ mode, pricingCategories }Standalone: { success: boolean }
iFrame: Promise<{ success: boolean }>
getPricingCategories()Standalone: { pricingCategories: PricingCategory[] }
iFrame: Promise<{ pricingCategories: PricingCategory[] }>
assignPricingCategories(input)AssignPricingCategoriesInputStandalone: { success, errors? }
iFrame: Promise<{ success, errors? }>
showToast(options)ShowToastOptionsStandalone: { success: boolean }
iFrame: Promise<{ actionClicked: boolean }>
showAlertDialog(options)ShowAlertDialogOptions{ success: boolean }
isDesignerReady(){ designerReady: boolean }
destroy()void

loadLayout(layoutData)

Description

Load an existing layout into the designer for editing.

Parameters

  • layoutData (LayoutOutput): The layout JSON from a previous export

Returns

{ success: boolean } — In standalone mode this is synchronous. In iframe SDK mode it returns a Promise<{ success: boolean }>.

Example

// Standalone mode (synchronous)
const { success } = SeatSquirrel.designer.loadLayout(savedLayout);

// Iframe SDK mode (async)
const { success } = await designer.loadLayout(savedLayout);
console.log('Layout loaded:', success);

getLayout({ mode })

Description

Get layout data from the designer. The mode parameter controls which snapshot is returned:

  • 'current' — Returns the real-time layout state including any unsaved changes.
  • 'last-saved' — Returns the last saved or loaded layout snapshot (not real-time). Returns null if no layout has been saved or loaded.

Note: getLayout({ mode: 'current' }) does not trigger the onSave callback. onSave only fires when the user clicks the Save button in the UI.

Parameters

  • options (Object):
PropertyTypeRequiredDescription
mode'current' | 'last-saved'YesWhich layout snapshot to return

Returns

{ layout: LayoutOutput | null } — In standalone mode this is synchronous. In iframe SDK mode it returns a Promise<{ layout: LayoutOutput | null }>. When mode is 'current', layout is always present. When mode is 'last-saved', layout may be null.

Example

// Standalone mode (synchronous)
const { layout } = SeatSquirrel.designer.getLayout({ mode: 'current' });

// Iframe SDK mode (async)
const { layout } = await designer.getLayout({ mode: 'current' });
console.log(layout);

// Get the last saved snapshot
const { layout: savedLayout } = designer.getLayout({ mode: 'last-saved' });
if (savedLayout) {
  console.log('Last saved:', savedLayout);
}

setPermissions(permissions)

Description

Set designer permissions at runtime. Use this to dynamically enable/disable features such as read-only mode, tool restrictions, or properties panel controls.

This method goes through the same permissions system as the constructor permissions option, so all permission fields are supported.

Parameters

Returns

{ success: boolean }

Example

// Enable read-only mode
designer.setPermissions({ readOnly: true });

// Disable read-only mode
designer.setPermissions({ readOnly: false });

// Enable assignment-only mode (pricing assignment only)
designer.setPermissions({ assignmentOnly: true });

// Disable specific tools at runtime
designer.setPermissions({ tools: { row: false, table: false } });

// Lock down properties panel
designer.setPermissions({
  properties: { pricingCategoriesCrud: false, currencySettings: false }
});

clearLayout()

Description

Clear the current layout and start with a blank canvas.

Returns

{ success: boolean }

Example

designer.clearLayout();

setPricingCategories({ mode, ... })

Description

Set or update pricing categories in the designer. The mode parameter controls how the categories are applied:

  • 'replace' — Replace all pricing categories with the provided array. Marks them as "externally managed" — users can only modify colors in the designer UI.
  • 'update-by-id' — Partially update existing categories by ID. Merges provided fields into matching categories while leaving unmentioned categories untouched. All-or-nothing: if any ID doesn't match an existing category, the entire call fails with no changes applied.
  • 'update-by-slug' — Partially update existing categories by slug. Merges provided fields into matching categories while leaving unmentioned categories untouched. All-or-nothing: if any slug doesn't match an existing category, the entire call fails with no changes applied.

Note: When using 'replace' mode, the designer UI restricts users to only modifying category colors. They cannot add, delete, or change pricing details.

Note: When using 'update-by-slug' mode, the slug field is used only for matching — it is not merged into the category. To change a category's slug, use 'update-by-id' mode and pass slug as an update field.

Parameters

  • options (Object):
PropertyTypeRequiredDescription
mode'replace' | 'update-by-id' | 'update-by-slug'YesHow to apply the pricing categories
pricingCategoriesArrayYesArray of pricing category objects (shape depends on mode)

Category Object Properties (mode: 'replace'):

PropertyTypeRequiredDescription
idstringYesUnique identifier for the category
labelstringYesDisplay label (e.g., "VIP", "Standard")
slugstringYesURL-friendly identifier
pricenumberYesPrice in cents (e.g., 15000 for $150)
colorstringYesHex color code (e.g., "#8b5cf6")
customerNotesstringNoOptional notes visible to customers

Update Object Properties (mode: 'update-by-id'):

PropertyTypeRequiredDescription
idstringYesID of the category to update (must match an existing category)
labelstringNoNew display label
slugstringNoNew slug
pricenumberNoNew price in cents
colorstringNoNew hex color code
customerNotesstringNoNew customer notes

Update Object Properties (mode: 'update-by-slug'):

PropertyTypeRequiredDescription
slugstringYesSlug of the category to match (used for lookup only, not merged)
labelstringNoNew display label
pricenumberNoNew price in cents
colorstringNoNew hex color code
customerNotesstringNoNew customer notes

Returns

{ success: boolean } — In standalone mode this is synchronous. In iframe SDK mode it returns a Promise<{ success: boolean }>.

Example

// Replace all categories (standalone, synchronous)
const result = SeatSquirrel.designer.setPricingCategories({
  mode: 'replace',
  pricingCategories: [
    { id: 'vip', label: 'VIP', slug: 'vip', price: 15000, color: '#8b5cf6' },
    { id: 'standard', label: 'Standard', slug: 'standard', price: 5000, color: '#3b82f6' },
  ]
});
console.log(result.success); // true

// Replace all categories (iframe SDK, async)
const result = await designer.setPricingCategories({
  mode: 'replace',
  pricingCategories: [
    { id: 'vip', label: 'VIP', slug: 'vip', price: 15000, color: '#8b5cf6' },
    { id: 'standard', label: 'Standard', slug: 'standard', price: 5000, color: '#3b82f6' },
    { id: 'economy', label: 'Economy', slug: 'economy', price: 2500, color: '#10b981' },
  ]
});
console.log('Pricing set:', result.success);

// Partially update by ID
const result = SeatSquirrel.designer.setPricingCategories({
  mode: 'update-by-id',
  pricingCategories: [
    { id: 'price_abc123', price: 7500, label: 'Standard (updated)' },
    { id: 'price_def456', color: '#10B981' },
  ]
});

// Partially update by slug
const result = await designer.setPricingCategories({
  mode: 'update-by-slug',
  pricingCategories: [
    { slug: 'standard', price: 7500, label: 'Standard (updated)' },
    { slug: 'vip', color: '#10B981' },
  ]
});

getPricingCategories()

Description

Get the current pricing categories from the designer.

Returns

{ pricingCategories: PricingCategory[] } — In standalone mode this is synchronous. In iframe SDK mode it returns a Promise<{ pricingCategories: PricingCategory[] }>.

Example

// Standalone mode (synchronous)
const { pricingCategories } = SeatSquirrel.designer.getPricingCategories();

// Iframe SDK mode (async)
const { pricingCategories } = await designer.getPricingCategories();
console.log(pricingCategories);

assignPricingCategories(input)

Description

Assign pricing categories to layout objects (rows, seats, areas, tables, table seats) programmatically. This is useful when pricing categories are managed externally and need to be mapped to layout objects after loading.

Atomic semantics: If any assignment fails validation, none are applied. All errors are returned in the errors array.

The mode parameter controls how objects and categories are identified:

  • 'by-id' — Reference objects and categories by their internal UUIDs.
  • 'by-slug' — Reference objects and categories by their user-defined slugs. This is the recommended mode.
  • 'dangerously-by-labels' — Reference objects by human-readable labels (can be ambiguous across sections). Categories are always referenced by slug in this mode.

Parameters

PropertyTypeRequiredDescription
mode'by-id' | 'by-slug' | 'dangerously-by-labels'YesHow to identify objects and categories

Additional properties for mode 'by-id' and 'by-slug':

Each property is a Record<key, categoryKeys[]> map (keys are IDs or slugs depending on mode).

PropertyTypeRequiredDescription
rowsRecord<string, string[]>NoRow assignments
rowSeatsRecord<string, string[]>NoSeat assignments
areasRecord<string, string[]>NoArea assignments
tablesRecord<string, string[]>NoTable assignments
tableSeatsRecord<string, string[]>NoTable seat assignments

Additional properties for mode 'dangerously-by-labels': Each property is an array of label-based entries with pricingCategorySlugs.

Returns

AssignPricingCategoriesResult { success: boolean, errors?: string[] } — In standalone mode this is synchronous. In iframe SDK mode it returns a Promise.

Example

// Assign by slug (recommended)
const result = SeatSquirrel.designer.assignPricingCategories({
  mode: 'by-slug',
  rows: {
    'row-a': ['vip', 'standard'],
    'row-b': ['standard'],
  },
  areas: {
    'vip-lounge': ['vip'],
  },
});

// Assign by ID
const result = await designer.assignPricingCategories({
  mode: 'by-id',
  rows: {
    'row-uuid-1': ['cat-uuid-1', 'cat-uuid-2'],
    'row-uuid-2': ['cat-uuid-2'],
  },
});

if (!result.success) {
  console.error('Assignment errors:', result.errors);
}

showToast(options)

Description

Show a toast notification inside the designer UI.

Parameters

  • options (Object):
PropertyTypeRequiredDescription
titlestringYesMain toast message
typestringNo'success', 'info', 'warning', 'error', or 'default' (default: 'default')
descriptionstringNoSecondary description text
actionObjectNoAction button: { label: string, onClick?: function }

Returns

  • Standalone mode: { success: boolean }
  • iFrame SDK mode: Promise<{ actionClicked: boolean }> — resolves when the toast is dismissed or the action button is clicked

Example

designer.showToast({ title: 'Layout saved successfully', type: 'success' });

// Per-toast action callback (works in both modes)
const { actionClicked } = await designer.showToast({
  title: 'External changes detected',
  type: 'info',
  description: 'Pricing was updated in your ticketing system.',
  action: {
    label: 'Reload pricing',
    onClick: function () {
      fetchLatestPricing().then(categories => designer.setPricingCategories({ mode: 'replace', pricingCategories: categories }));
    },
  },
});
console.log('User clicked action:', actionClicked);

Action handling by mode:

  • Standalone modeaction.onClick runs directly when the button is clicked.
  • iFrame SDK modeaction.onClick is called via correlation IDs when the action button is clicked. The returned Promise resolves with { actionClicked: true } if the action was clicked, or { actionClicked: false } if the toast was dismissed.

showAlertDialog(options)

Description

Show a modal alert dialog inside the designer UI. The dialog blocks interaction and requires the user to explicitly confirm or cancel.

Note: Only one alert dialog can be shown at a time. Calling showAlertDialog() while a dialog is open cancels the previous one. In both modes, onConfirm and onCancel work the same way. In iframe mode, the SDK matches callbacks via internal correlation IDs transparently.

Parameters

  • options (Object):
PropertyTypeRequiredDescription
titlestringYesDialog title text
descriptionstringNoDialog body/description text
confirmTextstringNoConfirm button label (default: 'OK')
cancelTextstringNoCancel button label (default: 'Cancel')
variantstringNo'default' or 'danger' — danger shows a red AlertTriangle icon (default: 'default')
modestringNo'alert' (OK button only) or 'confirm' (OK/Cancel buttons) (default: 'alert')
onConfirmfunctionNoCalled when the user clicks the confirm button
onCancelfunctionNoCalled when the user clicks the cancel button

Returns

{ success: boolean }

Example

designer.showAlertDialog({
  title: 'Unsaved changes',
  description: 'You have unsaved changes that will be lost. Continue?',
  variant: 'danger',
  confirmText: 'Discard changes',
  cancelText: 'Go back',
  onConfirm: function () {
    navigateAway();
  },
});

designer.showAlertDialog({
  title: 'Layout published',
  description: 'Your layout is now live and available for booking.',
  mode: 'alert',
});

hasChanges()

Description

Check if there are unsaved changes.

Returns

{ hasChanges: boolean } — Whether there are unsaved changes


isDesignerReady()

Description

Check if the designer is ready to receive commands.

Returns

{ designerReady: boolean } — Whether the designer is ready


destroy()

iFrame SDK only. Not available in standalone mode — standalone cleanup is handled automatically by the page lifecycle.

Description

Destroy the designer instance. Removes the iframe from the DOM, detaches the PostMessage event listener, and clears all internal state (pending requests, cached layouts, callback maps). Call this when you no longer need the designer — for example, when a modal closes or the user navigates away in a SPA.

Returns

void

Example

designer.destroy();

Next Steps