We developed a lightweight UI of the Printess Editor that integrates seemlessly into your shop system. It is not feature complete compared to our Panel UI, but it is way faster and does not require the user to leave the shop system at all.
A basic implementation of the Slim UI is very straightforward:
const r = await import("https://editor.printess.com/slim-ui.js");
const token = "[your-shop-token]"
const printess = await r.createSlimUi({
previewContainer: document.querySelector(".printess-preview"),
uiContainer: document.querySelector(".printess-ui"),
previewImage: document.querySelector(".printess-preview-image"),
loader: document.querySelector(".printess-image-loader"),
shopToken: token,
templateName: "Framed-Canvas-Slim",
published: false, // remove in production! The default is true = published version
theme: "",
lang: "de",
textUpdateTimeout: "short",
formFields: [{ name: "head", value: "Neue Überschrift" }]
});
document.getElementById("buttonBasket")
.addEventListener("click", async () => {
const data = await printess.createSaveToken();
prompt("Save Token:", data.saveToken);
prompt("Thumbnail Url:", data.thumbnailUrl);
});
As you can see, the process is fairly similar to the Panel UI, the main difference being that you need to have at least a <div class="printess-ui"></div> in your webpage for the UI to attach itself to.
templateName can also take the save-token you received from createSaveToken().
<header>
<h1>Slim-Ui on Product Description Page</h1>
<p>Slim-Ui is super light weight and offers only a limited feature set.
<br>It's intented to customize simple products directly on the PDP of you shop.</p>
</header>
<div class="main-grid">
<div class="printess-preview-container">
<div class="printess-preview">
<img class="printess-preview-image" />
<div class="printess-image-loader">
<svg class="circular" viewBox="25 25 50 50">
<circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="5" stroke-miterlimit="10" />
</svg>
</div>
</div>
</div>
<div>
<div class="printess-ui">
</div>
<button id="buttonBasket">Add to basket</button>
</div>
</div>
<script type="module">
const r = await import("https://editor.printess.com/slim-ui.js");
const token = "[your-shop-token]"
const printess = await r.createSlimUi({
previewContainer: document.querySelector(".printess-preview"),
uiContainer: document.querySelector(".printess-ui"),
previewImage: document.querySelector(".printess-preview-image"),
loader: document.querySelector(".printess-image-loader"),
shopToken: token, // "[your-shop-token]",
templateName: "Framed-Canvas-Slim", // "Children's book",
published: false,
theme: "",
lang: "de",
textUpdateTimeout: "short",
formFields: [{ name: "head", value: "Neue Überschrift" }]
});
document.getElementById("buttonBasket")
.addEventListener("click", async () => {
const data = await printess.createSaveToken();
console.log(data);
prompt("Save Token:", data.saveToken);
prompt("Thumbnail Url:", data.thumbnailUrl);
});
</script>
You give the createSlimUi() call an object that has to contain some data in order for it to work, such as a correct templateName, shopToken and uiContainer.
Additionally, some loading parameters give you options to influence the state in which the UI is initialized.
formFields accepts an array of objects, each containing the name of a form field and the value you want to be selected initially.
<header>
<h1>Slim-Ui on Product Description Page</h1>
<p>In this example, the selected color is Light Grey, as opposed to Black, which would be the default without setting in the formFields array.</p>
</header>
<div class="main-grid">
<div class="printess-preview-container">
<div class="printess-preview">
<img class="printess-preview-image" />
<div class="printess-image-loader">
<svg class="circular" viewBox="25 25 50 50">
<circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="5" stroke-miterlimit="10" />
</svg>
</div>
</div>
</div>
<div>
<div class="printess-ui">
</div>
<button id="buttonBasket">Add to basket</button>
</div>
</div>
<script type="module">
const r = await import("https://editor.printess.com/slim-ui.js");
const token = "[your-shop-token]";
const printess = await r.createSlimUi({
previewContainer: document.querySelector(".printess-preview"),
uiContainer: document.querySelector(".printess-ui"),
previewImage: document.querySelector(".printess-preview-image"),
loader: document.querySelector(".printess-image-loader"),
shopToken: token, // "[your-shop-token]",
templateName: "Framed-Canvas-Slim", // "Children's book",
published: false,
theme: "",
lang: "de",
textUpdateTimeout: "short",
formFields: [{ name: "frame", value: "Light Grey" }]
});
document.getElementById("buttonBasket")
.addEventListener("click", async () => {
const data = await printess.createSaveToken();
console.log(data);
prompt("Save Token:", data.saveToken);
prompt("Thumbnail Url:", data.thumbnailUrl);
});
</script>
The layout value accepts a string containing a Layout Snippet ID, which will be merged when the template is loaded.
You can find your Layout Snippet ID in the Account Portal.
<header>
<h1>Slim-Ui on Product Description Page</h1>
</header>
<div class="main-grid">
<div class="printess-preview-container">
<div class="printess-preview">
<img class="printess-preview-image" />
<div class="printess-image-loader">
<svg class="circular" viewBox="25 25 50 50">
<circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="5" stroke-miterlimit="10" />
</svg>
</div>
</div>
</div>
<div>
<div class="printess-ui">
</div>
<button id="buttonBasket">Add to basket</button>
</div>
</div>
<script type="module">
const r = await import("https://editor.printess.com/slim-ui.js");
const token = "[your-shop-token]";
const printess = await r.createSlimUi({
previewContainer: document.querySelector(".printess-preview"),
uiContainer: document.querySelector(".printess-ui"),
previewImage: document.querySelector(".printess-preview-image"),
loader: document.querySelector(".printess-image-loader"),
shopToken: token, // "[your-shop-token]",
templateName: "slim-merge-example",
layoutSnippetSearchTags: ["slim-portrait", "printess-canvas-portrait"],
published: false,
theme: "",
lang: "de",
textUpdateTimeout: "short",
layout: "sid~fc3b2184ba8dc6893385fa7408e4bb11f5d4fbf7~gid",
});
document.getElementById("buttonBasket")
.addEventListener("click", async () => {
const data = await printess.createSaveToken();
prompt("Save Token:", data.saveToken);
prompt("Thumbnail Url:", data.thumbnailUrl);
});
</script>
If you want your users to be able to select a Layout Snippet for their customisation, you need to give the loader the loadingParameter layoutSnippetSearchTags, which accepts an array of tags as strings, such as layoutSnippetSearchTags: ["slim-portrait", "printess-canvas-portrait"].
The menu only loads if you have at least one of the tags selected in the template in the Printess Editor and it only loads the tags selected there.
You can also load a Keyword Menu with the layoutSnippetMenuId loading parameter.

<header>
<h1>Slim-Ui on Product Description Page</h1>
</header>
<div class="main-grid">
<div class="printess-preview-container">
<div class="printess-preview">
<img class="printess-preview-image" />
<div class="printess-image-loader">
<svg class="circular" viewBox="25 25 50 50">
<circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="5" stroke-miterlimit="10" />
</svg>
</div>
</div>
</div>
<div>
<div class="printess-ui">
</div>
<button id="buttonBasket">Add to basket</button>
</div>
</div>
<script type="module">
const r = await import("https://editor.printess.com/slim-ui.js");
const token = "[your-shop-token]";
const printess = await r.createSlimUi({
previewContainer: document.querySelector(".printess-preview"),
uiContainer: document.querySelector(".printess-ui"),
previewImage: document.querySelector(".printess-preview-image"),
loader: document.querySelector(".printess-image-loader"),
shopToken: token, // "[your-shop-token]",
templateName: "slim-merge-example",
layoutSnippetSearchTags: ["slim-portrait", "printess-canvas-portrait"],
published: false,
theme: "",
lang: "de",
textUpdateTimeout: "short",
layout: "sid~fc3b2184ba8dc6893385fa7408e4bb11f5d4fbf7~gid",
});
document.getElementById("buttonBasket")
.addEventListener("click", async () => {
const data = await printess.createSaveToken();
prompt("Save Token:", data.saveToken);
prompt("Thumbnail Url:", data.thumbnailUrl);
});
</script>
If you want the snippet selection menu to start on a specific Category and Topic, you can use initialCategory: string and initialTopic: string to select the correct one.
This is useful when the Slim UI is embedded on a product description page for a specific occasion or style - for example a “Wedding” product page can open the layout menu directly on the matching category/topic instead of making the user search for it, while still letting them browse to a different one if they want.
const printess = await r.createSlimUi({
previewContainer: document.querySelector(".printess-preview"),
uiContainer: document.querySelector(".printess-ui"),
previewImage: document.querySelector(".printess-preview-image"),
loader: document.querySelector(".printess-image-loader"),
shopToken: token,
templateName: "Framed-Canvas-Slim",
initialCategory: "occasions",
initialTopic: "wedding"
});
<header>
<h1>Slim-Ui on Product Description Page</h1>
<p>In this example, the preselected Layout category should be "Occasions" and the keyword should be "Wedding". By default, the first of each would be selected.</p>
</header>
<div class="main-grid">
<div class="printess-preview-container">
<div class="printess-preview">
<img class="printess-preview-image" />
<div class="printess-image-loader">
<svg class="circular" viewBox="25 25 50 50">
<circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="5" stroke-miterlimit="10" />
</svg>
</div>
</div>
</div>
<div>
<div class="printess-ui">
</div>
<button id="buttonBasket">Add to basket</button>
</div>
</div>
<script type="module">
const r = await import("https://editor.printess.com/v/nightly/slim-ui.js");
const token = "[your-shop-token]";
const printess = await r.createSlimUi({
previewContainer: document.querySelector(".printess-preview"),
uiContainer: document.querySelector(".printess-ui"),
previewImage: document.querySelector(".printess-preview-image"),
loader: document.querySelector(".printess-image-loader"),
shopToken: token, // "[your-shop-token]",
templateName: "Framed-Canvas-Slim", // "Children's book",
published: false,
theme: "",
lang: "en",
textUpdateTimeout: "short",
formFields: [{ name: "frame", value: "Light Grey" }],
initialCategory: "occasions",
initialTopic: "wedding"
});
document.getElementById("buttonBasket")
.addEventListener("click", async () => {
const data = await printess.createSaveToken();
console.log(data);
prompt("Save Token:", data.saveToken);
prompt("Thumbnail Url:", data.thumbnailUrl);
});
</script>
You can enable/disable options of Select formfields through the load parameter formFieldListEnabledStates.
It takes an array of { ffName: string, states: iEnabledStates } and adjusts all the options specified for all the specified form fields.
const initialFormFieldListEnabledStates =
[
{
ffName: "DOCUMENT_SIZE",
states:
[
{
value: "40x50",
disabled: true
},
{
value: "40x40",
disabled: true
}
]
}
];
const printess = await r.createSlimUi({
previewContainer: document.querySelector(".printess-preview"),
uiContainer: document.querySelector(".printess-ui"),
previewImage: document.querySelector(".printess-preview-image"),
loader: document.querySelector(".printess-image-loader"),
shopToken: token,
templateName: "Framed-Canvas-Slim",
formFields: [{ name: "disabled", value: "metal-round" }],
formFieldListEnabledStates: initialFormFieldListEnabledStates
});
Any formfields and options not listed in formFieldListEnabledStates will not be changed.
<header>
<h1>Slim-Ui on Product Description Page</h1>
<p>In this example, the options 40x40cm and 40x50cm are disabled in the size selection.</p>
<button id="enableSelection">Click here to disable 42x84cm and enable the other options</button>
</header>
<div class="main-grid">
<div class="printess-preview-container">
<div class="printess-preview">
<img class="printess-preview-image" />
<div class="printess-image-loader">
<svg class="circular" viewBox="25 25 50 50">
<circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="5" stroke-miterlimit="10" />
</svg>
</div>
</div>
</div>
<div>
<div class="printess-ui">
</div>
<button id="buttonBasket">Add to basket</button>
</div>
</div>
<script type="module">
const r = await import("https://editor.printess.com/v/nightly/slim-ui.js");
const token = "[your-shop-token]";
const initialFormFieldListEnabledStates =
[
{
ffName: "DOCUMENT_SIZE",
states:
[
{
value: "40x50",
disabled: true
},
{
value: "40x40",
disabled: true
}
]
}
];
const printess = await r.createSlimUi({
previewContainer: document.querySelector(".printess-preview"),
uiContainer: document.querySelector(".printess-ui"),
previewImage: document.querySelector(".printess-preview-image"),
loader: document.querySelector(".printess-image-loader"),
shopToken: token,
templateName: "Framed-Canvas-Slim",
published: false,
formFieldListEnabledStates: initialFormFieldListEnabledStates
});
document.getElementById("buttonBasket")
.addEventListener("click", async () => {
const data = await printess.createSaveToken();
console.log(data);
prompt("Save Token:", data.saveToken);
prompt("Thumbnail Url:", data.thumbnailUrl);
});
const newStates =
[
{
value: "40x50",
disabled: false
},
{
value: "40x40",
disabled: false
},
{
value: "42x84",
disabled: true
}
];
document.getElementById("enableSelection").addEventListener("click", async () => {
printess.setFormFieldListDisabledStates("DOCUMENT_SIZE", newStates)
});
</script>
You can adjust Form Field properties when loading the slimUI using the load parameter formFieldProperties.
When adjusting a Select list through formFieldProperties, all options will be overwritten, no matter if they are specified in your parameter.
const formFieldProperties = [
{
name: "Select",
list: [
{ key: "red", label: "Red", description: "A warm red tone", tag: "color" },
{ key: "green", label: "Green", description: "A fresh green tone", tag: "color", disabled: true },
{ key: "blue", label: "Blue", description: "A calm blue tone", tag: "color" },
]
},
{
name: "Name",
regExp: "Fritz",
regExpMessage: "Name must be 'Fritz'"
}
];
const printess = await r.createSlimUi({
previewContainer: document.querySelector(".printess-preview"),
uiContainer: document.querySelector(".printess-ui"),
previewImage: document.querySelector(".printess-preview-image"),
loader: document.querySelector(".printess-image-loader"),
shopToken: token,
templateName: "Canvas-Slim-FF-Props",
textUpdateTimeout: "short",
formFieldProperties: formFieldProperties
});
<header>
<h1>Slim-Ui on Product Description Page</h1>
<p>In this example there are some changes to the FormFields:</p>
<ul>
<li>The Field Select has all its values overwritten</li>
<li>The Option "Green" in Select is disabled</li>
<li>The Validation & Validation Message of the Text Field "Name" is overwritten</li>
</ul>
</header>
<div class="main-grid">
<div class="printess-preview-container">
<div class="printess-preview">
<img class="printess-preview-image" />
<div class="printess-image-loader">
<svg class="circular" viewBox="25 25 50 50">
<circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="5" stroke-miterlimit="10" />
</svg>
</div>
</div>
</div>
<div>
<div class="printess-ui">
</div>
<button id="buttonBasket">Add to basket</button>
</div>
</div>
<script type="module">
const r = await import("https://editor.printess.com/v/nightly/slim-ui.js");
const token = "[your-shop-token]";
const formFieldProperties = [
{
name: "Select",
list: [
{ key: "red", label: "Red", description: "A warm red tone", tag: "color" },
{ key: "green", label: "Green", description: "A fresh green tone", tag: "color", disabled: true },
{ key: "blue", label: "Blue", description: "A calm blue tone", tag: "color" },
]
},
{
name: "Name",
regExp: "Fritz",
regExpMessage: "Name must be 'Fritz'"
}
];
const printess = await r.createSlimUi({
previewContainer: document.querySelector(".printess-preview"),
uiContainer: document.querySelector(".printess-ui"),
previewImage: document.querySelector(".printess-preview-image"),
loader: document.querySelector(".printess-image-loader"),
shopToken: token,
templateName: "Canvas-Slim-FF-Props",
formFieldProperties: formFieldProperties
});
document.getElementById("buttonBasket")
.addEventListener("click", async () => {
const data = await printess.createSaveToken();
console.log(data);
prompt("Save Token:", data.saveToken);
prompt("Thumbnail Url:", data.thumbnailUrl);
});
</script>
A few more loading parameters are worth knowing:
formFieldChangedCallback fires whenever a price relevant form field changes.renderPreviewImageCallback fires every time the preview image needs to be re-rendered.progressStateChangedCallback reports whenever the progress indicator is shown or hidden.priceCategoryLabels sets the price badge labels, just like in the Panel UI.disableProductImageUploadOnStartup delays the product image replacement until the first user interaction.includeGlobalLayoutSnippets overrides the include global layout snippets flag.The createSlimUi() call returns a reference to a JS/TS api, which you can utilise to enrich your shop with more functionality.
Following are some code examples of use cases that were inspired by our customers.
The benefits of the SlimUI come at a cost: It is not feature complete compared to the full Printess editor which you can use through the PanelUI. You might have a product that most of your users can easily customize to their wishes through the Slim options, but some want to take more control. For these you can offer a switch to the full editor experience in two simple steps.
First you must save the current state of settings in the slimUI to a saveToken: await slimApi.createSaveToken().
You can then use this saveToken to load the state in the PanelUI after loading it:
const printessPanel = await printessPanelLoader.load({
token: "[your-shop-token]",
templateName: "Framed-Canvas-Slim",
templateVersion: "published",
basketId: "Some-Unique-Basket-Or-Session-Id",
});
printessPanel.api.load(data.saveToken);
printessPanel.ui.show();
load<header>
<h1>Slim-Ui on Product Description Page</h1>
<p>You can switch from the Slim-Ui to our Panel-Ui, where users can fully customize their product.</p>
<p>By generating a saveToken in the Slim-Ui, you can load the Panel-Ui with all the customization that was already done.</p>
</header>
<div class="main-grid">
<div class="printess-preview-container">
<div class="printess-preview">
<img class="printess-preview-image" />
<div class="printess-image-loader">
<svg class="circular" viewBox="25 25 50 50">
<circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="5" stroke-miterlimit="10" />
</svg>
</div>
</div>
</div>
<div>
<div class="printess-ui">
</div>
<button id="buttonBasket">Add to basket</button>
<button id="buttonPanel">Panel UI</button>
</div>
</div>
<script type="module">
const r = await import("https://editor.printess.com/slim-ui.js");
const printessPanelLoader = await import("https://editor.printess.com/printess-editor/loader.js");
const token = "[your-shop-token]";
const printess = await r.createSlimUi({
previewContainer: document.querySelector(".printess-preview"),
uiContainer: document.querySelector(".printess-ui"),
previewImage: document.querySelector(".printess-preview-image"),
loader: document.querySelector(".printess-image-loader"),
shopToken: token, // "[your-shop-token]",
templateName: "Framed-Canvas-Slim",
published: false,
theme: "",
lang: "de",
textUpdateTimeout: "short",
formFields: [{ name: "frame", value: "Light Grey" }]
});
document.getElementById("buttonBasket")
.addEventListener("click", async () => {
const data = await printess.createSaveToken();
prompt("Save Token:", data.saveToken);
prompt("Thumbnail Url:", data.thumbnailUrl);
});
document.getElementById("buttonPanel")
.addEventListener("click", async () => {
const data = await printess.createSaveToken();
const printessPanel = await printessPanelLoader.load({
token: "[your-shop-token]",
templateName: "Framed-Canvas-Slim",
templateVersion: "published",
basketId: "Some-Unique-Basket-Or-Session-Id",
})
printessPanel.api.load(data.saveToken);
printessPanel.ui.show();
});
</script>
loadYou can enable or disable options depending through the API method setFormFieldListDisabledStates().
It takes the name of the formfield you wish to adjust and iEnabledStates.
const newStates =
[
{
value: "40x50",
disabled: false
},
{
value: "40x40",
disabled: false
},
{
value: "42x84",
disabled: true
}
];
printess.setFormFieldListDisabledStates("DOCUMENT_SIZE", newStates);
<header>
<h1>Slim-Ui on Product Description Page</h1>
<p>In this example, the options 40x40cm and 40x50cm are disabled in the size selection.</p>
<button id="enableSelection">Click here to disable 42x84cm and enable the other options</button>
</header>
<div class="main-grid">
<div class="printess-preview-container">
<div class="printess-preview">
<img class="printess-preview-image" />
<div class="printess-image-loader">
<svg class="circular" viewBox="25 25 50 50">
<circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="5" stroke-miterlimit="10" />
</svg>
</div>
</div>
</div>
<div>
<div class="printess-ui">
</div>
<button id="buttonBasket">Add to basket</button>
</div>
</div>
<script type="module">
const r = await import("https://editor.printess.com/v/nightly/slim-ui.js");
const token = "[your-shop-token]";
const initialFormFieldListEnabledStates =
[
{
ffName: "DOCUMENT_SIZE",
states:
[
{
value: "40x50",
disabled: true
},
{
value: "40x40",
disabled: true
}
]
}
];
const printess = await r.createSlimUi({
previewContainer: document.querySelector(".printess-preview"),
uiContainer: document.querySelector(".printess-ui"),
previewImage: document.querySelector(".printess-preview-image"),
loader: document.querySelector(".printess-image-loader"),
shopToken: token,
templateName: "Framed-Canvas-Slim",
published: false,
formFieldListEnabledStates: initialFormFieldListEnabledStates
});
document.getElementById("buttonBasket")
.addEventListener("click", async () => {
const data = await printess.createSaveToken();
console.log(data);
prompt("Save Token:", data.saveToken);
prompt("Thumbnail Url:", data.thumbnailUrl);
});
const newStates =
[
{
value: "40x50",
disabled: false
},
{
value: "40x40",
disabled: false
},
{
value: "42x84",
disabled: true
}
];
document.getElementById("enableSelection").addEventListener("click", async () => {
printess.setFormFieldListDisabledStates("DOCUMENT_SIZE", newStates)
});
</script>