Develop your own widget - XMPieLab/uStore-NG GitHub Wiki
XMPie provides a sample Widget SDK which you can download and use as a sample to create your own custom uStore widgets.
- uStore 26.3 and above: Node.js 24.
- uStore 17.0 to 26.2: Node.js 16 and above.
React version: a widget never bundles its own React. Its build externalizes react, react-dom and prop-types to the globals the storefront publishes, so a widget always runs against the host storefront's React — 19.2.8 on uStore 26.3, 18.2.0 on 25.2–26.2. Do not add React to your widget's bundle.
Download and unzip the sample application for your uStore version:
| uStore version | Sample application |
|---|---|
| 26.3 and above | widget_project_sample_26.3.zip |
| 17.0 to 26.2 | widget_project_sample_17.2.zip |
| 16 | widget_project_sample.zip |
The 26.3 sample is a separate download because both the Node floor and the React version changed; one package cannot serve both.
The information below is also provided in the README.md file included in the above zips.
-
Each Widget must be contained inside a root folder that is named with a distinctive name, using
A-Z a-zand_characters only. For example:sample_widget_1. If you mean to keep maintenance and develop further versions, it is best to add the version number to the widgets name, to keep uniqueness. -
Each Widget project must contain to following files:
- config.json
- thumbnail.png
- src/index.widget.js
In the sample project folder you'll notice some extra files, which are not mandatory and are there for development/build purposes. It is important not to alter these files, to keep the project's features active.
The config.json file includes vital configurations in a JSON format:
-
engineVersionThe unique version of the widget. Accepted characters:0-9and. -
uStoreVersionThe uStore version of which the widget was first built to. Important for backwards compatibility. Accepted characters:0-9and. -
uniqueIdentifierThe unique name for the widget. If uploading to uStore a widget with a uniqueIdentifier that already exists, the new one will override the existing one. Accepted characters:A-Z,a-zand_ -
displayNameDisplay name for the widget, which will be shown in uStore. -
descriptionDescription for the widget purposes -
configurationHelpTextInstructions on how to configure the widget -
defaultConfigurationWidget's configuration, JSON format works the best
To support the widgets, the uStore theme must have a widgets property under the customization property inside its config.json file. The config will list all the available Slots in the theme.
Each slot will have the following configurations:
-
nameunique name for the slot -
displayNamea display name for the slot Example:
{
"engineVersion": "1",
"uStoreVersion": "15.4.10900",
"name": "AquaBlue",
"displayName": "XMPie AquaBlue",
"customization": {
"widgets": {
"locations": [
{
"name": "header",
"displayName": "Header"
}
]
},
.
.
.
|-- widget_project_sample
|-- .babelrc
|-- .gitignore
|-- package.json
|-- webpack.config.js
|-- scripts
| |-- build-user.js
| |-- dev.js
|-- xmpie_Sample_1
|-- config.json
|-- thumbnail.png
|-- public
| |-- index.html
|-- src
| |-- index.js
| |-- index.widget.js
|-- styles
|-- index.widget.css
From uStore 26.3 the storefront runs on React 19. A widget package uploaded to uStore contains no React of its own, so a widget built for an earlier version keeps working without being rebuilt. Only the project source needs attention, and only in one place.
src/index.js is the standalone development entry — the file that mounts the widget when you run npm start. React 19 removed ReactDOM.render, so replace it:
// before
ReactDOM.render(<Widget />, document.getElementById('root'))
// after
import { createRoot } from 'react-dom/client'
createRoot(document.getElementById('root')).render(<Widget />)src/index.widget.js — the real widget entry — mounts nothing and does not change.
If a third-party React package in your project declares a peer range ending at React 18, add an overrides entry pointing at the project's pinned React rather than installing with --legacy-peer-deps, which permits a second React runtime in which every hook throws:
"overrides": {
"some-react-18-package": { "react": "$react", "react-dom": "$react-dom" }
}Install with NPM
cd widget_project_sample
npm installBy running the dev command, you'll be able to see the widget as-is, not inside an existing theme. As each widget is a stand-alone component that must be able to run by its own, the development environment will let you see each change you make to your widget component.
To run the development environment simply run
npm startBy default, the development environment will run a webpack dev server under the port 9000.
The published script will locate every parent folder that contains a src/index.widget.js file and will generate a separate zip file for it.
You may publish your widget by running the build command, that will generate a zip file compatible to the project requirements. This zip file can be uploaded to UStore as a new widget.
-
If the folder contains a
config.jsonfile, the project will be built according to the configurations inside this file, just by runningnpm run build
-
If you wish to use our built-in widget configuration generator, you may remove the
config.jsonfile or running the commandnpm run build --config
To develop a widget and see it a specific slot/slots inside the theme, you may run the npm start command with the widgetbuild parameter. The parameter may refer to a location of a folder that contains one Widget/few Widgets.
The configuration for the widgets will be taken according to the following logic:
-
Widgets that doesn't have local development folder to which
widgetbuildparameter points, and exist in uStore, will have their configuration taken from uStore server. -
Widgets that have local development folder and also exist in uStore will have their config from the local
config.jsonfile. If the widget has local slot configuration(seeLocal Slot Configuration), it will override the configuration set in uStore. -
Widgets that have local development folder and doesn't exist in uStore, will have their configuration from their local
config.jsonfile and their location configuration according to how its set (via json config file).
Create a JSON file, in any name, and any location, and point to this file using the json parameter. For example:
npm start server=10.0.0.1 widgetbuild=C:\Users\MyBrand\widgets json=C:\Users\MyBrand\Documents\widgets.slot.config.jsonThe widget slot configuration file contains an object, which its keys are locations and values are arrays which contain the widgets unique identifiers.
The widgets unique identifiers you can find in config.json in the field uniqueIdentifier of your widget.
{
"footer": ["xmpie_Sample_1", "xmpie_Sample_2", "xmpie_Sample_3"],
}
Example where config.json is stored
|-- xmpie_Sample_1
|-- config.json
You can add prefixes to your css classes. To add some certain prefix you need to go to postcss.config.mjs and add a value for a prefix key.
Example:
prefix: 'xw-featured-'To start adding prefixes, you need to enter the following code. This code will add prefixes in working files. Note depending on the operating system there are cases that a path needs to be enclosed in quotes.
With quotes:
npm run postcss "add/your-path/*.css"
Without quotes:
npm run postcss add/your-path/*.css