--- title: "10.5.0 - 3D Product Configurator Integrations Guide" slug: "10-5-0-3d-product-configurator-integrations-guide" updated: 2026-06-09T15:57:14Z published: 2026-06-09T15:57:14Z canonical: "developers.3dcloud.com/10-5-0-3d-product-configurator-integrations-guide" --- > ## Documentation Index > Fetch the complete documentation index at: https://developers.3dcloud.com/llms.txt > Use this file to discover all available pages before exploring further. # 10.5.0 - 3D Product Configurator Integrations Guide ## Implementing On Your Website The 3D Product Configurator front end code can be implemented on customer facing websites through several methods. Defined below are options an implementing developer can use to integrate with a website. ### Front End Application Supported Browsers and Devices | Chrome | 51+ | | --- | --- | | Firefox | 54+ | | Edge | 14+ | | Safari | 10+ (*except 15.0; 15.1+ supported)* | | Opera | 38+ | | Internet Explorer | Not supported | | Edge iOS | Not supported | ### Front End Application URL Parameters ● `?config=<configId>` ○ The Id of the configurator to load, used for debugging purposes a developer should pass in the configurator id in the initialization functions of the API for production use. ● `?storeId=<storeId>` ○ Store Id used for Analytics ● `?sku=<sku>` ○ Sku of the current chair loaded, auto updated on swapping steps ● `?preview=<true/false>` ○ This parameter is for testing purposes only and will force the application to always load the latest version of the configurator. ### Adding the library from the 3D Cloud CDN Ask your account team for your specific CDN URLs. 1. JS example: 1. https://cdn.3dcloud.io/{client_specific_folder}/x.x.x/MxtProductConfigurator-x.x.x.js 2. Minified JS example (should be used in production environments) 1. https://cdn.3dcloud.io/{client_specific_folder}/x.x.x/MxtProductConfigurator-x.x.x.min.js 3. CSS example: 1. https://cdn.3dcloud.io/{client_specific_folder}/x.x.x/MxtProductConfigurator-x.x.x.css 4. Initiating the application example: ```xml    MxtModularConfigurator Example            
          ``` #### Initialization When initializing, there are two things that MUST be true about the HTML element that you pass in (or the parent element for the viewer container, see the Components section below) 1. It **MUST have a defined height and width**, whether that is an absolute value (like 600px) or a percentage of its parent that has an absolute value (for example 50% of the page width/height). This is because the 3d canvas has no defined size in and of itself, so we have no “size to build out”, so to speak. Additionally, if a size is NOT given, the 3d render engine will spin out of control attempting to render in a 0x0 space. 2. (for 3d render type only) It **MUST be not be** `display:none` while the engine is running. By default, the engine starts running on `init`. IF you want to init the MxtKongfigurator in a hidden container, use the option `spin3d.loadPaused`. The 3d renderer will spin out of control when attempting to render to a non-visible container. By using the option `spin3d.loadPaused`, the renderer will start in a paused mode. In order to start the rendering engine when the container is made visible, call the `run()` method. To re-pause the renderer, call the `stop()` method. ### Minimum Required Options When constructing the class for the product configurator there are required options and optional options that you will set for the product configurator to function properly. These are the three required options that you must always set. | **Option Name** | **Option Description** | | --- | --- | | spinCommon.apiKey | API Key provided by 3D Cloud™**(required)** | | configurationId | the unique id of the configurator to load **(required)** | | spinCommon.element | The element that the Configurator will be built within. Some sort of specific height and width must be given, otherwise the app will not have any size. This is due to the fact that the rendering canvas has no inherent size. **(required)** | | configuratorBrowserId | The unique id of the configurator browser step to load on startup inside the configurator when using a step type configurator browser and you want to override the default choice in the configurator data. | ### Basic Optional Options These options are optional and are the most commonly set by developers implementing the product configurator on their website. #### SpinCommon options These options are applicable to the render view for both 2d and 3d renders, and live under spinCommon, i.e. ```typescript const configurator = new MxtProductConfigurator.MxtKongfigurator({    spinCommon: {        apiKey: '{user api key provided by 3D Cloud}',        ...    }, }); ``` apiKey and element are covered above. | **Option Name** | **Option Description** | | --- | --- | | `loadingIconColor` | CSS string defining color of loading progress bar. | | `loadingIconBackgroundColor` | CSS string defining color of loading progress bar background. | | ```typescript services?: { environment?: MSServiceEnvironment; }; ``` | The environment of services to hit. Defaults to production. | | logging | Sets the log level which can be pulled from log.levels namespace; ```typescript TRACE: 0; DEBUG: 1; INFO: 2; WARN: 3; ERROR: 4; SILENT: 5; ``` Defaults to WARN | #### AR Options Part spinCommon options. ```typescript webArMode?: WebArMode; webArOptions?: MxtSpinsWebArOptions; ``` `WebArMode` defaults to `WebArMode.None`. - `WebArMode.Pregenerated` will attempt to get an AR asset that has already been generated and stored based on the current sku(s). If none exists, then no web AR asset will be available. - `WebArMode.OnDemand` will look up an existing AR asset based on sku(s), but if one does not exist, a new one will be generated when a user requests one. `webArOptions.enableScaling` - `by default, scaling on USDZ is turned off. If you wish to enable, set this flag` #### Customizing Text and Icons Options This only applies to spinCommon options: To customize icons used in the renderer view: ```typescript icons: {    about?: string;    close?: string;    collapse?: string;    presetView?: string;    presetViewActive?: string;    download?: string;    downloadInverse?: string;    downloadActive?: string;    expand?: string;    rotateLeft?: string;    rotateRight?: string;    spinner?: string;    webAr?: string;    webArInverse?: string;    zoomIn?: string;    zoomOut?: string; } ``` To customize text: `customText` in the format `{[language: string]: any;}` where language is a language ISO code ([https://www.metamodpro.com/browser-language-codes](https://www.metamodpro.com/browser-language-codes)), for example: ```typescript customText : {    en: {      about: {          appName: "My example app name"      }    }     }; ``` Rather than providing an exhaustive list of every available key, please contact us with the text you desire to override, and we will provide you with the appropriate key(s). ### spin3d Options These options are applicable to the render view for 3d renders only, and live under spin3d, i.e. ```typescript const configurator = new MxtProductConfigurator.MxtKongfigurator({    spin3d: {        camera: {}        ...    }, }); ``` | **Option Name** | **Option Description** | | --- | --- | | `loadPaused` | Use this if you dont want the 3d render loop to start immediately upon initialization. Use especially if you are initializing in a hidden div or one with no size. Call run() method to start the 3d render loop whenever the div becomes visible. | | `zoomDelta` | `Zoom Delta - in meters; defaults to .3` | | `rotateDelta` | `Rotate Delta - in radians; defaults to .3` | | `fitToScreenMultiplier` | The amount of screen that a product should “fill” when initially loaded; essentially default zoom level but relative to product size | | `maxDistanceMultiplier` | Effectively max zoom, relative to the default zoom level | | `showGuidance` | `If not provided, defaults to on if panning is turned on, and defaults to off if panning is turned off. If true, then will create guidance with panning guidance if panning is allowed, and guidance without panning if panning is not allowed` | #### Camera Options Part spin3d options. All nested within a “camera” options object, i.e. ```typescript spin3d: {    camera: {      allowPanning: true,      ...    } }, ``` | **Option Name** | **Option Description** | | --- | --- | | `allowPanning` | If true, right click pans the camera rather than rotates the camera. Panning is limited to bounds of product. | | `defaultAlpha`, `defaultBeta` | ![](https://cdn.us.document360.io/26506022-6aab-411f-8cd9-6f97246fc64f/Images/Documentation/ee4f393c-3f8d-476d-a499-d01210a043ab) | | `lowerBetaLimit` | `Minimum camera angle that the camera can rotate vertically` | | `upperBetaLimit` | `Maximum camera angle that the camera can rotate vertically` | | `lowerAlphaLimit` | Minimum camera angle that the camera can rotate horizontally | | `upperAlphaLimit` | Maximum camera angle that the camera can rotate horizontally | #### Hotspot Options Part spin3d options. All nested within a “hotspots” options object, i.e. ```typescript spin3d: {    hotspots: {      invisibleOnLoad: true,      ...    } }, ``` | **Option Name** | **Option Description** | | --- | --- | | `invisibleOnLoad` | There is a hotspot toggle in the UI. By default, hotspots show up when there are hotspots and the UI toggle is on. This defaults the UI toggle to off so that the user has to manually toggle the hotspots on. | | `hotspotMeshBasePath` | URL base path for a hotspot mesh; we provide a default hotspot mesh, but a custom one can be provided by using this + `hotspotMeshFilename` | | `hotspotMeshFilename` | Filename of hotspot mesh. Must be a GLB/GLTF file. URL is created by doing `hotspotMeshBasePath` + `hotspotMeshFilename`. | #### Customizing 3D viewer Icon Options This only applies to spin3d options: To customize icons used in the 3drenderer view: ```typescript icons: {    hotspotToggle?: string;    hotspotToggleActive?: string;    hotspotToggleInverse?: string;    dimensions?: string;    dimensionsActive?: string;    dimensionsInverse?: string;    panningGuidanceMouse?: string;    panningGuidanceMousePan?: string;    panningGuidanceDrag?: string;    panningGuidanceTwoFingerDrag?: string; } ``` #### Dimension Options Part spin3d options. All nested within a “dimensions” options object, i.e. ```typescript spin3d: {    dimensions: {      enabled: true      ...    } }, ``` | **Option Name** | **Option Description** | | --- | --- | | `enabled` | Enable/disable dimensions. Enabled by default | | `color` | Color of dimension lines: `{ r: 0.5921, g: 0.5921, b: 0.5921, a: 1 }` by default (light blue) | | `unitType` | Unit type to display for dimensions; defaults to inches. | | `visibleOnLoad` | If dimensions should be visible on load. Defaults to off, users must toggle it on | | `lineScale` | Size of line | | `arrowScale` | Size of arrows at the end of the line | #### Preset Views Options Part spin3d options. All nested within a “`presetViews`” options object, i.e. ```typescript spin3d: {    presetViews: {      enabled: true      ...    } }, ``` | **Option Name** | **Option Description** | | --- | --- | | `enabled` | Enable/disable preset views. Enabled by default | | `views` | We supply default preset views. To override these, provide an array of objects in format: ```typescript { id: string; displayName: string; icon: string; azimuth: number; elevation: number; } ``` | #### Screenshot Options Part spin3d options. All nested within a “screenshot” options object, i.e. ```typescript spin3d: {    screenshot: {      width: 1024      ...    } }, ``` | **Option Name** | **Option Description** | | --- | --- | | `enabled` | By default, enabled. | | `width` | `By default, screenshot 1024x1024. May specify a different width, or set to -1 to use size on screen`. If using a value other than -1, note that cropping may occur if your aspect ratio on screen does not match the aspect ratio defined here | | `height` | `By default, screenshot 1024x1024. May specify a different height, or set to -1 to use size on screen`. If using a value other than -1, note that cropping may occur if your aspect ratio on screen does not match the aspect ratio defined here | | `hiResWidth` | `By default, hi res screenshot 4096x4096. May specify a different width, or set to -1 to use size on screen`. If using a value other than -1, note that cropping may occur if your aspect ratio on screen does not match the aspect ratio defined here | | `hiResHeight` | `By default, hi res screenshot 4096x4096. May specify a different height, or set to -1 to use size on screen`. If using a value other than -1, note that cropping may occur if your aspect ratio on screen does not match the aspect ratio defined here | | `waterMarkPlugin` | Provide a watermark for your screenshot downloads | | `downloadImagePlugins` | By default, we provide certain downloads (jpg and png). If you want to provide more/different types, use these plugins to add more. | | `imageFilename` | By default, the downloaded image gets a filename of the sku; override this to provide a custom imageFilename | #### spin2d options These options are applicable to the render view for 2d renders only, and live under spin2d, i.e. ```typescript const configurator = new MxtProductConfigurator.MxtKongfigurator({    spin2d: {        zoomDisabled: true        ...    }, }); ``` | **Option Name** | **Option Description** | | --- | --- | | `zoomDisabled` | Use this to disable zoom controls and not allow the user to look at a zoomed in (higher resolution) render | | `backgroundColor` | `Default is white, format is {r:number, g:number, b:number, a:number} where each value goes from 0->1, inclusive` | #### Configurator Level Options These options are applicable to the configurator in general and live at the root level of options ```typescript const configurator = new MxtProductConfigurator.MxtKongfigurator({    assetEnvironment: MxtKongfigAssetEnvironment.STAGING    ... }); ``` | **Option Name** | **Option Description** | | --- | --- | | `renderType` | 2d or 3d or none. Defaults to 3d. | | `assetEnvironment` | ```typescript enum MxtKongfigAssetEnvironment { LATEST = "Latest", TEST = "Test", STAGING = "Stage", PRODUCTION = "Active" } ``` Use PRODUCTION for your production environment and STAGING for your cert environment, and TEST for your test enviroment. LATEST includes works-in-progress configurators and shouldn’t be used generally by clients. | | `skuUrlParam` | `By default, we auto-update the URL parameter 'sku' with the current sku. Use this to change the url parameter to something other than 'sku'` | | `initialSkus` | If you want to load a particular sku that is different than the default sku that a configurator model would naturally load | | ```typescript colors?: { primary: IColor3; secondary: IColor3; dropShadow: IColor3; }; ``` | Sets the primary color, secondary color, and drop shadow (used on certain buttons). Secondary color is used for the pricing, as well as the gradient color on the main CTA Many more color options can be set via css variables; see custom CSS section. | | `backgroundColor` | Background color of the renderer only (not of the UI). Use any valid css string | | `backgroundColorOnScreenshots` | Background color to use for screenshots; may be different than the normal background color | | `baseShareUrl` | Ordinarily, for sharing, we share a link that points back to the current HTTP address of the page; override this to point to a custom page. Current URL search params are added to this url. | | heading | Override the default camera heading in degrees, for 3d render type only | | `pitch` | Override the default camera pitch in degrees, for 3d render type only | | zoom | Override the default zoom, for 3d render type only | | `showStepNumber` | By default, our UI does not show the step number next to steps; make this true to show step number | | `icons` | ```typescript { sif?: string; sifInverse?: string; bom?: string; bomInverse?: string; crm?: string; crmInverse?: string; atc?: string; atcInverse?: string; share?: string; shareInverse?: string; virtualAssistantButton?: string; missing?: string; paginationFirst?: string; paginationLast?: string; paginationRight?: string; paginationLeft?: string; blocked?: string; info?: string; back?: string; help?: string; sectionArrow?: string; close?: string; alert?: string; searchIcon?: string; chevronDown?: string; stepGroupArrow?: string; } ``` | | maxFrameRate | ```typescript /** Max Frame Rate; the maximum frame rate for the renderer */ maxFrameRate?: number; ``` | | renderQualityLevel | ```typescript /** Quality Level; the desired quality level for the renderer, this locks to this value if provided 0 (Low), 1 (Medium), 2 (High), 3 (Ultra) */ renderQualityLevel?: QualityLevel; ``` | ### Advanced Options, Plugins, and Callbacks #### Plugins There are number of different plugins available to override or add to Configurator. Analytics: `spinCommon.analyticsPlugin` - Provide a custom analytics plugin; you would probably want to extends `Kong3dSpinsAnalyticsPlugin` or `Kong2dSpinsAnalyticsPlugin` depending on if it is a 2d or 3d render type. All other plugins are passed in via `spinCommon.plugins.` Plugins that are NOT provided by default: - `KongPluginTypes.BOM` - add a plugin that implements `IConfiguratorBomPlugin` and handles creating a bill of materials - `KongPluginTypes.ATC` - add a plugin that implements `IConfiguratorAddToCartPlugin` and handles adding to cart - `KongPluginTypes.CRM` - add a plugin that implements `IConfiguratorCRMPlugin` and handles doing CRM - `PLUGIN_TYPE.CONFIG_PRICING` - add a plugin that implements `IConfiguratorPricingPlugin` and handles doing CRM Plugins that provide a default, but you may want to override: - `RendererPluginType.SIF` - add a plugin that extends `SIFPlugin` and provides custom behavior/SIF resolution - `KongPluginTypes.HELP_ME_DECIDE` - add a plugin that extends `KongHelpMeDecidePlugin` and provides custom UI for the help me decide modal - `KongPluginTypes.OPTION_PAGE` - add a plugin that extends `OptionPagePlugin` and provides custom UI for the options UI - `KongPluginTypes.STEP_PAGE` - add a plugin that extends `StepPagePlugin` and provides custom UI for the steps UI - `KongPluginTypes.OPTION_POPOVER` - add a plugin that extends `OptionPopoverPlugin` and provides custom UI for the tooltip on options When creating a plugin, there is an *id* field that must be provided on the plugin (it is provided on all of our default plugins). If you want the same plugin to be used for every single configurator, use id = DEFAULT_PLUGIN_ID. If you want to use a different plugin for different configurators, then provide plugins with custom id fields, that match the plugin id field on the configurator model. #### Changing Currently Loaded SKU programmatically You can set the current SKU in the current configurator to load/show via this public function on the MxtKongfigurator class. `async setSkus(skus: string[], keepCameraAngle = false): Promise<void>` `MxtKongfigurator.setSkus(...)` #### Functions for External Control of the Configurator The `IConfiguratorDataAPI` interface exposes a simplified, read-only view of the configurator's current state. It is implemented by `MxtKongfigurator` and designed for programmatic (including AI) clients to query configurator data without needing to understand the full internal architecture. #### *Initializing MxtKongfigurator* Before you can use `IConfiguratorDataAPI`, you need to create and initialize an `MxtKongfigurator` instance. #### *Required Options* | **Property** | **Type** | **Description** | | --- | --- | --- | | `spinCommon.apiKey` | `string` | Your MXT API key | | `spinCommon.element` | `HTMLDivElement` | The DOM element to render into (required if `parentElements` is not set) | | `assetEnvironment` | `MxtKongfigAssetEnvironment` | One of: `LATEST`, `TEST`, `STAGE`, `STAGING`, `PRODUCTION` | #### *Basic Initialization* `import { MxtKongfigurator } from './kongfigurator/MxtKongfigurator'; ` `import { MxtKongfigAssetEnvironment } from '@mxt/mxt-js-renderer-core/lib/configurable/model/MxtKongfigAssetEnvironment'; ` `const parentElement = document.getElementById('configurator-container') as HTMLDivElement; ` `const configurator = new MxtKongfigurator({ spinCommon: { apiKey: 'YOUR_API_KEY', element: parentElement, }, assetEnvironment: MxtKongfigAssetEnvironment.PRODUCTION, initialSkus: ['SKU1', 'SKU2'], // optional: load specific SKUs on start configurationId: 'your-config-id', // optional: load a specific configuration }); ` `await configurator.init();` #### *Initialization with iframe Communication* When the configurator is hosted inside an iframe and you need the parent window to communicate with it via `postMessage`, pass an `iframeCommunicator`: `import { MxtKongfiguratorIFrameCommunicator } from './kongfigurator/ui/MxtKongfiguratorIFrameCommunicator'; ` `const isInIframe = window.self !== window.top; ` `const configurator = new MxtKongfigurator({ ` `spinCommon: { ` `apiKey: 'YOUR_API_KEY', ` `element: parentElement, ` `}, ` `assetEnvironment: MxtKongfigAssetEnvironment.PRODUCTION, iframeCommunicator: isInIframe ? new MxtKongfiguratorIFrameCommunicator(targetOrigin) : undefined, ` `}); ` `await configurator.init();` The `targetOrigin` should be the origin of the parent window (e.g., `'https://your-site.com'`). When running in iframe context, this is typically read from a URL query parameter (`targetOrigin`), falling back to `window.origin`. #### *Lifecycle* `// Create and initialize const configurator = new MxtKongfigurator(options); ` `await configurator.init(); ` `// Use the Data API ` `const state = configurator.getConfiguratorState(); ` `// Clean up when done ` `configurator.destroy();` --- ## **Interface Definition** `export interface IConfiguratorDataAPI { ` `getConfiguratorInfo(): MxtConfiguratorController; ` `getConfiguratorState(): { ` `[stepId: string]: {` `selectedOptionId: string; ` `visible: boolean ` `} ` `}; ` `getStepInfo(stepId: string): MxtConfiguratorStep; ` `getOptionInfo(stepId: string, optionId: string): MxtConfiguratorOption;` `getAvailableSteps(): MxtConfiguratorStep[]; ` `getAvailableOptions(stepId: string): MxtConfiguratorOption[]; ` `}` `MxtKongfigurator` implements this interface directly, so all methods are available on any `MxtKongfigurator` instance after `init()` completes. --- ## **API Methods** ### **getConfiguratorInfo** `getConfiguratorInfo(): MxtConfiguratorController` Returns the full `MxtConfiguratorController`, which is the central controller managing all configurator state. Use this when you need access to the complete configurator model, current product, SKU information, or need to call controller methods like `selectOption()` or `loadSKU()`. **Example:** `const controller = configurator.getConfiguratorInfo(); ` `// Access the current product ` `const product = controller.currentProduct; ` `// Access current SKUs ` `const skus = controller.currentSkus; // string[] ` `const sku = controller.currentSku; // combined string ` `// Access the full model ` `const allSteps = controller.model.steps;` ### **getConfiguratorState** `getConfiguratorState(): { [stepId: string]: { selectedOptionId: string; visible: boolean } }` Returns a serialized snapshot of the current configurator state as a map of step IDs to their current selection and visibility. This iterates over **all** steps (not just visible ones). - `selectedOptionId` can be `undefined` if the step is hidden or has no way to set a default due to current rules. - `visible` indicates whether the step is currently visible based on configurator rules. **Example:** `const state = configurator.getConfiguratorState(); ` `for (const [stepId, { selectedOptionId, visible }] of Object.entries(state)) { ` `console.log(`Step ${stepId}: selected=${selectedOptionId}, visible=${visible}`); ` `} ` `// Example output: ` `// Step color: selected=opt_red, visible=true ` `// Step size: selected=opt_large, visible=true ` `// Step accessory: selected=undefined, visible=false` --- ### **getStepInfo** `getStepInfo(stepId: string): MxtConfiguratorStep` Returns the full `MxtConfiguratorStep` object for a given step ID. Uses the model's internal `stepMap` for O(1) lookup. **Example:** `const step = configurator.getStepInfo('color'); ` `console.log(step.name); // "Color" ` `console.log(step.label); // Display label ` `console.log(step.options.length); // Number of options in this step` `console.log(step.isVisible); // Base visibility flag` ### **getOptionInfo** `getOptionInfo(stepId: string, optionId: string): MxtConfiguratorOption` Returns the full `MxtConfiguratorOption` object for a specific option within a step. Internally calls `getStepInfo(stepId)` then looks up the option from the step's `optionMap`. **Example:** `const option = configurator.getOptionInfo('color', 'opt_red');` `console.log(option.name); // "Red" ` `console.log(option.label); // Display label` `console.log(option.skuComponentCode); // SKU component code for this option ` `console.log(option.price); // Price value ` `console.log(option.image); // Thumbnail image URL` --- ### **getAvailableSteps** `getAvailableSteps(): MxtConfiguratorStep[]` Returns only the steps that are currently **visible** based on the configurator's rule engine. This delegates to the controller's `getVisibleSteps()` method. **Example:** `const visibleSteps = configurator.getAvailableSteps(); ` `for (const step of visibleSteps) { ` `console.log(`${step.id}: ${step.name}`); ` `}` --- ### **getAvailableOptions** `getAvailableOptions(stepId: string): MxtConfiguratorOption[]` Returns only the options that are currently **visible** for a given step, based on the configurator's rule engine. This delegates to the controller's `getVisibleOptions()` method. **Example:** `const visibleOptions = configurator.getAvailableOptions('color'); ` `for (const option of visibleOptions) { ` `console.log(`${option.id}: ${option.label} ($${option.price})`); ` `}` --- ## **Using the Data API via iframe Messages** When the configurator runs inside an iframe, the parent window can access the Data API through `postMessage`. The `MxtKongfiguratorIFrameCommunicator` listens for incoming messages and responds with the corresponding data. ### **Message Protocol** **Send a request** from the parent window: `const iframe = document.getElementById('configurator-iframe');` `iframe.contentWindow.postMessage( ` `{ ` `type: 'MESSAGE_TYPE', ` `data: { /* optional parameters */ }, ` `}, ` `targetOrigin ` `);` **Listen for the response** in the parent window: `window.addEventListener('message', (event) => { ` `if (event.data.type === 'RESPONSE_TYPE') { ` `const result = event.data.data; // handle the result ` `} ` `});` ### **Data API Message Types** | Request type | Request data | Response type | Response data | | --- | --- | --- | --- | | 'getConfiguratorInfo' | (none) | 'getConfiguratorInfo' | MxtConfiguratorController | | 'getConfiguratorState' | (none) | 'getConfiguratorState' | { [stepId]: { selectedOptionId, visible } } | | 'getStepInfo' | { stepId: string } | 'getStepInfo' | MxtConfiguratorStep | | 'getOptionInfo' | { stepId: string, optionId: string } | 'getOptionInfo' | MxtConfiguratorOption | | 'getAvailableSteps' | (none) | 'getAvailableOptions' | MxtConfiguratorStep[] | | 'getAvailableOptions' | { stepId: string } | 'getAvailableOptions' | MxtConfiguratorOption[] | ### **Additional iframe Message Types** Beyond the Data API, the iframe communicator supports these operational messages: | Request `type` | Description | Response `type` | | --- | --- | --- | | `'screenshot'` | Take a screenshot (optional: `mimeType`, `color`, `horizontalAngle`, `verticalAngle`, `distance`) | `'screenshot'` | | `'displayedSteps'` | Get displayed/sorted steps | `'displayedSteps'` | | `'render-data'` | Get render generation data (product, camera, sku, backgroundColor) | `'render-data'` | | `'start-bulk-sku-render'` | Start bulk SKU rendering | `'bulk-render-progress'` / `'bulk-render-complete'` / `'bulk-render-error'` | | `'validate-sku'` | Validate a SKU array (`{ skus: string[] }`) | `'validate-sku-response'` | | `'allows-bulk-single-renders-request'` | Check bulk render support | `'allows-bulk-single-renders-response'` | | `'update-init-options'` | Merge partial `MxtKongfiguratorOptions` at runtime | (none) | ### **iframe Example** `// Parent window code ` `const iframe = document.getElementById('configurator-iframe'); ` `const KONGFIG_ORIGIN = 'https://kongfigurator.example.com'; ` `// Request the current configurator state iframe.contentWindow.postMessage({ type: 'getConfiguratorState' }, KONGFIG_ORIGIN); ` `// Request info about a specific step ` `iframe.contentWindow.postMessage( { type: 'getStepInfo', stepId: 'color', }, KONGFIG_ORIGIN ); ` `// Request available options for a step iframe.contentWindow.postMessage( { type: 'getAvailableOptions', stepId: 'color', }, KONGFIG_ORIGIN ); ` `// Listen for responses ` `window.addEventListener('message', (event) => { ` `if (event.origin !== KONGFIG_ORIGIN) return; ` `switch (event.data.type) { ` `case 'getConfiguratorState': ` `console.log('State:', event.data.data); ` `break; ` `case 'getStepInfo': ` `console.log('Step:', event.data.data); ` `break; ` `case 'getAvailableOptions': ` `console.log('Options:', event.data.data); ` `break; ` `} ` `});` --- ## **Configurator Notifications** The MXT platform uses a global pub/sub system called `NotificationCenter` to broadcast configurator lifecycle events. The `ConfiguratorMessageType` enum defines typed notification names that fire when configurator state changes (option selected, step visibility changed, SKU calculated, etc.). ### **NotificationCenter API** `NotificationCenter` is a singleton imported directly from `@mxt/mxt-services`. It is **not** accessed via `.Instance()` -- you import and use it directly. `import { NotificationCenter } from '@mxt/mxt-services/lib/notifications/NotificationCenter';` #### **Methods** | Method | Signature | Description | | --- | --- | --- | | `subscribe` | `subscribe(notificationName: string, method: (arg: any) => void, once?: boolean): void` | Subscribe a callback to a notification. Set `once: true` to auto-unsubscribe after the first call. If using a member function, use `.bind(this)`. | | `unsubscribe` | `unsubscribe(notificationName: string, method: (arg: any) => void): void` | Unsubscribe a callback. Must pass the same function reference used in `subscribe`. | | `post` | `post(notificationName: string, data?: Object): void` | Post a notification to all subscribers. Data should be an object, not a primitive. | | `waitForOneNotification` | `waitForOneNotification(notificationName: string): Promise<any>` | Returns a Promise that resolves the next time the notification fires (subscribes with `once: true` internally). | | `clearAll` | `clearAll(): void` | Removes all subscribers for all notifications. Called internally by `MxtKongfigurator.destroy()`. | #### **Basic Usage** `import { NotificationCenter } from '@mxt/mxt-services/lib/notifications/NotificationCenter'; ` `import { ConfiguratorMessageType } from '@mxt/mxt-js-renderer-core/lib/configurable/interfaces/ConfiguratorNotifications'; ` `// Subscribe to option selection changes ` `const onOptionSelected = (data) => { ` `console.log(`Step ${data.stepId}: ${data.prevOptionId} -> ${data.nextOptionId}`); ` `};` `NotificationCenter.subscribe(ConfiguratorMessageType.AFTER_SELECT_OPTION, onOptionSelected); // Clean up when done` `NotificationCenter.unsubscribe(ConfiguratorMessageType.AFTER_SELECT_OPTION, onOptionSelected);` #### **Using** `once` **for One-Time Listeners** `// Listen for the next SKU calculation only ` `NotificationCenter.subscribe(` `ConfiguratorMessageType.AFTER_CALCULATE_SKU, ` `(data) => { ` `console.log(`New SKU: ${data.nextSku}`); ` `}, ` `true // auto-unsubscribes after first call ` `); ` `// Or use the Promise-based version ` `const data = await NotificationCenter.waitForOneNotification(` `ConfiguratorMessageType.AFTER_CALCULATE_SKU ` `); ` `console.log(`New SKU: ${data.nextSku}`);` #### **Using with Class Methods** When subscribing with a class method, use `.bind(this)` and keep the bound reference for unsubscribing: `class MyComponent { ` `constructor() { ` `this.onOptionSelected = this.onOptionSelected.bind(this);` `NotificationCenter.subscribe( ConfiguratorMessageType.AFTER_SELECT_OPTION, this.onOptionSelected ); ` `} ` `onOptionSelected(data) { ` `console.log(`Selected: ${data.nextOptionId}`); ` `} ` `destroy() { ` `NotificationCenter.unsubscribe( ConfiguratorMessageType.AFTER_SELECT_OPTION, this.onOptionSelected ); ` `} ` `}` --- ### **ConfiguratorMessageType** All configurator lifecycle notifications follow a `BEFORE_*` / `AFTER_*` pattern. `BEFORE_*` fires before the state change is applied; `AFTER_*` fires after. `import { ConfiguratorMessageType } from '@mxt/mxt-js-renderer-core/lib/configurable/interfaces/ConfiguratorNotifications';` | Enum Value | String | Description | | --- | --- | --- | | `BEFORE_SELECT_OPTION` | `"Configurator_Before_Select_Option"` | Before an option is selected | | `AFTER_SELECT_OPTION` | `"Configurator_After_Select_Option"` | After an option is selected | | `BEFORE_SET_SELECTED_OPTION` | `"Configurator_Before_Set_Selected_Option"` | Before a selected option is set on the controller | | `AFTER_SET_SELECTED_OPTION` | `"Configurator_After_Set_Selected_Option"` | After a selected option is set on the controller | | `BEFORE_SET_STEP_VISIBLE` | `"Configurator_Before_Set_Step_Visible"` | Before step visibility changes | | `AFTER_SET_STEP_VISIBLE` | `"Configurator_After_Set_Step_Visible"` | After step visibility changes | | `BEFORE_SET_STEP_ORDER` | `"Configurator_Before_Set_Step_Order"` | Before step sort order changes | | `AFTER_SET_STEP_ORDER` | `"Configurator_After_Set_Step_Order"` | After step sort order changes | | `BEFORE_SET_OPTION_OVERRIDE` | `"Configurator_Before_Set_Option_Override"` | Before an option override (e.g. price) is applied | | `AFTER_SET_OPTION_OVERRIDE` | `"Configurator_After_Set_Option_Override"` | After an option override is applied | | `BEFORE_SET_OPTION_VISIBLE` | `"Configurator_Before_Set_Option_Visible"` | Before option visibility changes | | `AFTER_SET_OPTION_VISIBLE` | `"Configurator_After_Set_Option_Visible"` | After option visibility changes | | `BEFORE_SET_OPTION_ORDER` | `"Configurator_Before_Set_Option_Order"` | Before option sort order changes | | `AFTER_SET_OPTION_ORDER` | `"Configurator_After_Set_Option_Order"` | After option sort order changes | | `BEFORE_SET_SELECTED_MESH` | `"Configurator_Before_Set_Selected_Mesh"` | Before the selected mesh changes | | `AFTER_SET_SELECTED_MESH` | `"Configurator_After_Set_Selected_Mesh"` | After the selected mesh changes | | `BEFORE_SET_SELECTED_MATERIAL` | `"Configurator_Before_Set_Selected_Material"` | Before the selected material changes | | `AFTER_SET_SELECTED_MATERIAL` | `"Configurator_After_Set_Selected_Material"` | After the selected material changes | | `BEFORE_SET_MATERIALS` | `"Configurator_Before_Set_Materials"` | Before materials list changes | | `AFTER_SET_MATERIALS` | `"Configurator_After_Set_Materials"` | After materials list changes | | `BEFORE_CALCULATE_SKU` | `"Configurator_Before_Calculate_SKU"` | Before SKU recalculation | | `AFTER_CALCULATE_SKU` | `"Configurator_After_Calculate_SKU"` | After SKU recalculation | | `BEFORE_LOAD_PRODUCT_ASSEMBLY` | `"Configurator_Before_Load_Product_Assembly"` | Before a product assembly loads | | `AFTER_LOAD_PRODUCT_ASSEMBLY` | `"Configurator_After_Load_Product_Assembly"` | After a product assembly loads | | `BEFORE_DESTROY` | `"Configurator_Before_Destroy"` | Before the configurator is destroyed | | `AFTER_DESTROY` | `"Configurator_After_Destroy"` | After the configurator is destroyed | | `BEFORE_SAVE_DEFAULT_PRODUCT_ASSEMBLY_IDS` | `"Configurator_Before_Save_Default_Product_Assembly_Ids"` | Before default assembly IDs are saved | | `AFTER_SAVE_DEFAULT_PRODUCT_ASSEMBLY_IDS` | `"Configurator_After_Save_Default_Product_Assembly_Ids"` | After default assembly IDs are saved | ### **Notification Payloads** Each notification type carries a specific payload. The full type mapping is available via `ConfiguratorNotificationPayloadMap`. #### **Option Selection** Used by: `BEFORE_SELECT_OPTION`, `AFTER_SELECT_OPTION`, `BEFORE_SET_SELECTED_OPTION`, `AFTER_SET_SELECTED_OPTION` `interface ConfiguratorSelectOptionPayload { ` `stepId: string; prevOptionId: string; nextOptionId: string; ` `}` #### **Step Visibility** Used by: `BEFORE_SET_STEP_VISIBLE`, `AFTER_SET_STEP_VISIBLE` `interface ConfiguratorStepVisiblePayload { ` `stepId: string; prevVisible: boolean | null; nextVisible: boolean; ` `}` #### **Step Order** Used by: `BEFORE_SET_STEP_ORDER`, `AFTER_SET_STEP_ORDER` `interface ConfiguratorStepOrderPayload { ` `stepId: string; prevOrder: number | null; nextOrder: number; ` `}` #### **Option Override** Used by: `BEFORE_SET_OPTION_OVERRIDE`, `AFTER_SET_OPTION_OVERRIDE` `interface ConfiguratorOptionOverridePayload { ` `stepId: string; ` `optionId: string; ` `prevOverride: MxtConfiguratorOverride | null; ` `nextOverride: MxtConfiguratorOverride; ` `} ` `// MxtConfiguratorOverride = { price?: number }` #### **Option Visibility** Used by: `BEFORE_SET_OPTION_VISIBLE`, `AFTER_SET_OPTION_VISIBLE` `interface ConfiguratorOptionVisiblePayload { ` `stepId: string; ` `optionId: string; ` `prevVisible: MxtConfiguratorOptionVisibility | null; nextVisible: MxtConfiguratorOptionVisibility; ` `} ` `// MxtConfiguratorOptionVisibility: DO_NOT_SHOW = 0, VISIBLE = 1, UNAVAILABLE = 2` #### **Option Order** Used by: `BEFORE_SET_OPTION_ORDER`, `AFTER_SET_OPTION_ORDER` `interface ConfiguratorOptionOrderPayload { ` `stepId: string; ` `optionId: string; ` `prevOrder: number | null; ` `nextOrder: number; ` `}` #### **Mesh Selection** Used by: `BEFORE_SET_SELECTED_MESH`, `AFTER_SET_SELECTED_MESH` `interface ConfiguratorSelectedMeshPayload { ` `componentName: string; ` `prevMeshId: string | null; ` `nextMeshId: string | null; ` `}` #### **Material Selection** Used by: `BEFORE_SET_SELECTED_MATERIAL`, `AFTER_SET_SELECTED_MATERIAL` `interface ConfiguratorSelectedMaterialPayload {` `componentName: string; ` `prevMaterial: string | null; ` `nextMaterial: string; ` `}` #### **Materials List** Used by: `BEFORE_SET_MATERIALS`, `AFTER_SET_MATERIALS` `interface ConfiguratorMaterialsPayload { ` `componentName: string; ` `prevMaterials: string[] | null; ` `nextMaterials: string[]; ` `}` #### **SKU** **Calculation** `// BEFORE_CALCULATE_SKU interface ConfiguratorBeforeCalculateSkuPayload { prevSku: string | null; prevSkus: string[] | null; } // AFTER_CALCULATE_SKU interface ConfiguratorAfterCalculateSkuPayload { prevSku: string | null; prevSkus: string[] | null; nextSku: string; nextSkus: string[]; }` #### **Product Assembly** `// BEFORE_LOAD_PRODUCT_ASSEMBLY interface ConfiguratorBeforeLoadProductAssemblyPayload {` `prevProductId: string | null; ` `} ` `// AFTER_LOAD_PRODUCT_ASSEMBLY interface` `ConfiguratorAfterLoadProductAssemblyPayload {` `prevProductId: string | null; ` `nextProductId: string | null; ` `}` #### **Destroy** Used by: `BEFORE_DESTROY`, `AFTER_DESTROY` `interface ConfiguratorDestroyPayload { ` `prevProductId: string | null; ` `}` #### **Save Default Assembly IDs** `// BEFORE_SAVE_DEFAULT_PRODUCT_ASSEMBLY_IDS ` `interface ConfiguratorBeforeSaveDefaultAssemblyIdsPayload { ` `productId: string; ` `prevStepIds: string[] | null; ` `} ` `// AFTER_SAVE_DEFAULT_PRODUCT_ASSEMBLY_IDS ` `interface ConfiguratorAfterSaveDefaultAssemblyIdsPayload { ` `productId: string; ` `prevStepIds: string[] | null; ` `nextStepIds: string[]; ` `}` --- ### **Application-Level Notifications** In addition to the typed `ConfiguratorMessageType` notifications, the application posts several string-based notifications: | Notification Name | Payload | Description | | --- | --- | --- | | `'MxtKongfigurator_Config_Loaded'` | `MxtConfiguratorFile` | Fired after a configuration file is loaded | | `'ConfiguratorSectionExpand'` | `{ section }` | Fired when a configurator section expands | | `'HotspotLinkCallback'` | `{ step: MxtConfiguratorStep, hotspot: KongHotspot }` | Fired when a hotspot link is clicked | **Example -- listening for config load:** `const onConfigLoaded = (configFile) => {` `console.log('Configuration loaded:', configFile.id);` `};` `NotificationCenter.subscribe('MxtKongfigurator_Config_Loaded', onConfigLoaded); ` `// Clean up` `NotificationCenter.unsubscribe('MxtKongfigurator_Config_Loaded', onConfigLoaded);` --- ## **Key Types Reference** ### **MxtConfiguratorStep** | Property | Type | Description | | --- | --- | --- | | `id` | `string` | Unique step identifier | | `name` | `string` | Step name | | `label` | `string` | Display label | | `isVisible` | `boolean` | Base visibility flag | | `displayType` | `StepDisplayTypes` | How the step is displayed in the UI | | `image` | `string` | Step thumbnail image URL | | `camera` | `MxtConfiguratorCamera` | Camera settings for this step | | `options` | `MxtConfiguratorOption[]` | All options in this step | | `optionMap` | `Map<string, MxtConfiguratorOption>` | O(1) lookup map for options by ID | | `skuComponentOrder` | `number` | Order of this step's component in the SKU | | `filters` | `MxtConfiguratorFilter[]` | Filters applicable to this step | | `help` | `MxtConfiguratorHelp` | Help content for this step | | `properties` | `MxtConfiguratorOptionProperty[]` | Custom properties | | `propertiesMap` | `Map<string, MxtConfiguratorOptionProperty>` | Property lookup map | | `hotspots` | `KongHotspot[]` | Hotspot definitions | ### **MxtConfiguratorOption** | Property | Type | Description | | --- | --- | --- | | `id` | `string` | Unique option identifier | | `name` | `string` | Option name | | `label` | `string` | Display label | | `skuComponentCode` | `string` | SKU component code for this option | | `price` | `number` | Price value | | `image` | `string` | Thumbnail image URL | | `components` | `MxtRenderComponent[]` | Render components | | `filters` | `MxtConfiguratorFilterData[]` | Filter data | | `tooltipHeader` | `string` | Tooltip header text | | `tooltipBody` | `string` | Tooltip body text | | `helpImage` | `string` | Help image URL | | `helpLabel` | `string` | Help label | | `properties` | `MxtConfiguratorOptionProperty[]` | Custom properties | | `propertiesMap` | `Map<string, MxtConfiguratorOptionProperty>` | Property lookup map | ### **MxtConfiguratorController (key members)** | Member | Type | Description | | --- | --- | --- | | `model` | `DeepReadonly<MxtConfiguratorFile>` | The full configurator model | | `currentProduct` | `Product` | Currently loaded product | | `currentSkus` | `string[]` | Current SKU array | | `currentSku` | `string` | Combined SKU string | | `getSelectedOption(step)` | `DeepReadonly<MxtConfiguratorOption>` | Get the selected option for a step | | `isStepVisible(step)` | `boolean` | Check if a step is visible | | `getVisibleSteps()` | `DeepReadonly<MxtConfiguratorStep>[]` | Get all visible steps | | `getVisibleOptions(step)` | `DeepReadonly<MxtConfiguratorOption>[]` | Get visible options for a step | | `selectOption(step, option)` | `Promise<void>` | Select an option | | `loadSKU(skus)` | `Promise<MxtConfiguratorLoadResult>` | Load a SKU | #### Custom Error Handling ```typescript callbacks?: {    /** Allow for overriding of the error handling. Return false to prevent our default error handling, return true to continue our normal error handling */    onError?: (e: PromiseRejectionEvent) => boolean; }; ``` By default, we handle errors by presenting an error modal to the user. If you want custom behavior, then override this method. To prevent our default modal, make sure you return false from the callback. #### Custom Expand/Collapse ```typescript spinCommon: {    expandButton?: {        onExpand?: () => void;        onCollapse?: () => void;    }; }, ``` The picker (if present) will automatically be hidden onExpand and restored onCollapse. However, if you want to take additional action on expand/collapse, hook into these callbacks ### Components ![](https://cdn.us.document360.io/26506022-6aab-411f-8cd9-6f97246fc64f/Images/Documentation/5a980d1f-d96f-4466-be40-502632d1305b) Default Layout By default, the configurator builds out all of the UI in the format below underneath the HTML element provided in the options: ![](https://cdn.us.document360.io/26506022-6aab-411f-8cd9-6f97246fc64f/Images/Documentation/fa88dd61-1eb9-4283-add0-20c6dc62b4c1) However, we provide the ability for each UI components to be parented independently to best provide the needs for your custom UI. The list of components are: | **Component Type** | **Component Typescript Class** | **Component CSS Class** | **Notes** | | --- | --- | --- | --- | | `CombinedComponentType.PICKER_CONTAINER` | `PickerContainerComponent` | `.mxt-canvas-picker` | Contains the UI for picking steps/options, as well as the header/sku/pricing/etc (by default). Basically everything that isn’t the renderer | | `CombinedComponentType.VIEWER_CONTAINER` | `ViewerContainerComponent` | `.mxt-configurator-viewer` | The container for the renderer. Contains both the renderer itself and the button bar for the renderer. | | `CombinedComponentType.PICKER_SCROLLABLE` | `PickerScrollableComponent` | `.mxt-configurator-scrollable` | The scrollable section of the picker; see diagram above, depending on device contains different things. | | `CombinedComponentType.MODALS` | `ModalComponent` | `.mxt-modal-container` | Container for all modals; by default overlays both the picker container and viewer container | | `CombinedComponentType.VIEWER` | `ViewerComponent` | `.mxt-canvas-container` | Contains the actual renderer. | | `CombinedComponentType.BUTTON_BAR` | `ButtonBarComponent` | `.mxt-spin-button-row` | Buttons for manipulating renderer (zoom/rotate/etc) | | `CombinedComponentType.WEB_AR` | `WebArComponent` | `.mxt-webAr-container` | Button to trigger WebAR | | `CombinedComponentType.ABOUT` | `AboutComponent` | `.mxt-about-button` | Button to trigger About modal | | `CombinedComponentType.DOWNLOAD` | `DownloadButtonComponent` | `.mxt-btn-download` | Download screenshot button on button bar | | `CombinedComponentType.DIMENSIONS` | `DimensionsButtonComponent` | `.mxt-btn-dimensions` | Toggle dimensions button on button bar | | `CombinedComponentType.HOTSPOTS` | `HotspotButtonComponent` | `.mxt-btn-hotspot` | Toggle hotspots button on button bar | | `CombinedComponentType.PRESET_VIEW` | `PresetViewButtonComponent` | `.mxt-btn-preset-view` | Show preset view modal button on button bar | | `CombinedComponentType.EXPAND_BUTTON` | `ExpandButtonComponent` | `.mxt-btn-expand` | Expand/collapse renderer view | | `CombinedComponentType.STEPS` | `StepsComponent` | `.mxt-configurator-steps` | Container to show steps; uses `StepPagePlugin` to build UI within it | | `CombinedComponentType.OPTIONS` | `OptionsComponent` | `.mxt-configurator-options` | Container to show options; uses `OptionPagePlugin` to build UI within it | | `CombinedComponentType.HEADER` | `HeaderComponent` | `.mxt-configurator-header` | Header label (name of configurator) | | `CombinedComponentType.SUBHEADER` | `SubheaderComponent` | `.mxt-configurator-subheader` | Subheader label | | `CombinedComponentType.SKU` | `HeaderSkuComponent` | `.mxt-configurator-header-sku` | Sku label | | `CombinedComponentType.PRICING` | `PricingComponent` | `.mxt-configurator-total-pricing` | Pricing label | | `CombinedComponentType.CTAS` | `CTAContainerComponent` | `.mxt-configurator-ctas` | CTA container | | `CombinedComponentType.CTA_SHARE` | `ShareComponent` | `.mxt-configurator-cta-share` | Share button, only shows if enabled for configurator model | | `CombinedComponentType.CTA_ATC` | `ATCComponent` | `.mxt-configurator-cta-atc` | Add to cart button, only shows if there is an Add to cart plugin | | `CombinedComponentType.CTA_SIF` | `SIFComponent` | `.mxt-configurator-cta-sif` | SIF button, only shows if sif is enabled in app config | | `CombinedComponentType.CTA_CRM` | `CRMComponent` | `.mxt-configurator-cta-crm` | CRM button, only shows if there is a crm plugin | | `CombinedComponentType.CTA_BOM` | `BOMComponent` | `.mxt-configurator-cta-bom` | BOM button, only shows if there is a bom plugin | ![](https://cdn.us.document360.io/26506022-6aab-411f-8cd9-6f97246fc64f/Images/Documentation/96a4141c-b98a-49b6-9b48-d103628b5640) Components Diagram 1 ![](https://cdn.us.document360.io/26506022-6aab-411f-8cd9-6f97246fc64f/Images/Documentation/6ad622ec-7b01-4a61-a08c-d2b88180f2bb) Components Diagram 2 #### Customizing Component Locations There is an option `parentElements`. This allows you to provide a different parent element for any given component type. You do not need to provide a parent element for each; you can pick and choose which ones you need to customize. For example, if you have your own section you want to put your CTAs, you could just provide: ```typescript parentElements: {  ctas?: HTMLElement; } ``` It is possible to provide custom parents for everything. However, a much more common use case is to just re-parent several smaller components (such as CTA_SHARE or WEB_AR). In that case, use both the spinCommon.element option to set the main parent over everything, and just define the parentElements that would not fall in their default location. IF YOU DO NOT PROVIDE spinCommon.element (for example if you need to provide different parents for the picker container component and the viewer container component), then we will not create a root element to house everything else. This is a totally valid case, but If a root is not created, we cannot always automatically handle resize events. There are many edge cases where your parent elements may have been configured in a way that a resize event on one effects the size of the other. As a result, we turn off handling landscape vs portrait mode automatically. IF you believe you have a fairly standard setup, you may turn resizing back on via the option `autoResizeAllParents`. Component parents may be updated at runtime via ```typescript  updateParentElement(key: string | SpinsComponentType | KongComponentType, newParent: HTMLElement, removeOldParent?: boolean): void { ``` or ```typescript  updateParentElements(newParentElements: MxtKongParentComponentOptions, removeOldParents?: Boolean): void { ``` #### Disabling Components Components may be disabled via the option `disabledComponents`. It is possible to provide non-sensical situations, such as disabling the CTA container but not disabling the CTAs within it. An exception will be thrown in these cases. In order to disable all picker components (for example if you are building the UI yourself and just using our MxtKongfigurator for the renderer), use the option `disableAllPickerComponents`.