Migrate a Custom Element Extension

Add a custom element extension to your new Wix CLI project as part of migrating an app from the legacy Wix CLI.

Folder structure

Legacy pathNew path
src/site/widgets/custom-elements/<name>/element.jsonsrc/extensions/site/widgets/<name>/<name>.extension.ts
src/site/widgets/custom-elements/<name>/element.tsxsrc/extensions/site/widgets/<name>/<name>.tsx
src/site/widgets/custom-elements/<name>/panel.tsxsrc/extensions/site/widgets/<name>/<name>.panel.tsx
src/site/widgets/custom-elements/<name>/element.module.csssrc/extensions/site/widgets/<name>/<name>.module.css

Note: <name> is your extension's folder name in the legacy project. The new folder and files use the same name.

Step 1 | Copy and rename the files

In the new project:

  1. Create the folder src/extensions/site/widgets/<name>/.
  2. From the legacy project's src/site/widgets/custom-elements/<name>/ folder, copy the following files into the new folder, and rename them:
    • element.tsx to <name>.tsx
    • panel.tsx, if present, to <name>.panel.tsx
    • element.module.css, if present, to <name>.module.css

Don't copy the legacy element.json file. You recreate its values in <name>.extension.ts.

Step 2 | Adapt the code to the new project

In <name>.tsx and <name>.panel.tsx:

  1. Update any imports as needed, to use the new paths.
  2. If either file calls a web method or an HTTP function, replace the call. Fixing the import path isn't enough, because the legacy backend code doesn't exist in that form after the migration. See Migrate from Web Methods to HTTP Endpoints or Migrate from HTTP Functions to HTTP Endpoints.

Step 3 | Create the extension file

In the new project:

  1. In src/extensions/site/widgets/<name>/, create <name>.extension.ts.

  2. Add the following code, and set each field to the value the table below specifies:

    Copy
    FieldSource in legacy projectWhat to specify
    idid in element.jsonCopy source as is
    namename in element.jsonCopy source as is
    widthwidth in element.jsonCopy source as is, including allowStretch and stretchByDefault if your legacy config sets them. Only defaultWidth is required.
    heightheight in element.jsonCopy source as is
    installation.autoAddinstallation.autoAddToSite in element.jsonCopy source as is, or false if the legacy config doesn't set it
    tagNameNoneThe extension folder name
    elementNonePath to <name>.tsx, relative to src/
  3. Add any of the following fields that apply, inside the same object. Add essential to the existing installation object, not as a second installation field:

    Copy
    FieldSource in legacy projectWhat to specifyCondition
    installation.essentialinstallation.essential in element.jsonCopy source as isOnly if your legacy element.json sets it
    presetspresets in element.jsonCopy the preset's id and thumbnailUrl, and add a name, which legacy presets don't have. Use the element's name, which is the preset name the legacy CLI writes to the app manifest. If the thumbnailUrl references a local assets/ folder, see Update the preset thumbnail URL.Only if your legacy element.json sets it
    behaviorsbehaviors in element.json, such as the dashboard page the widget links toCopy source as isOnly if your legacy element.json sets it
    settingsNonePath to <name>.panel.tsx, relative to src/Only if the legacy extension has a panel.tsx file

Important: The id must match the value from the legacy element.json. Otherwise, the new entry is treated as a separate extension instead of a continuation of the legacy one.

Update the preset thumbnail URL

A legacy custom element has at most 1 preset. If its thumbnailUrl references a local assets/ folder, replace the value with {{BASE_URL}}/thumbnail.png:

Copy

Move the image itself into the new project's public/ folder, which is where {{BASE_URL}} resolves to.

Step 4 | Register the extension

In the new project, in src/extensions.ts:

  1. Import the extension:

    Copy
  2. Add a .use() call for it to the app() chain, on its own line:

    Copy

Step 5 | Return to the main migration guide

Return to Install the extension's dependencies in the main migration guide.

Last updated: 10 November 2026

Did this help?