Slim UI integration

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().

Example Code - Full CodePen Source
<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 can see a live example of this basic Slim UI implementation here

Loading Parameters

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.

Initial Form Field values

formFields accepts an array of objects, each containing the name of a form field and the value you want to be selected initially.

Example Code - Full CodePen Source
<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>
You can see a life demo of this here

Merge Snippet on load

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.

Example Code - Full CodePen Source
<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>
See a demo of this

Load Layout Snippet selection

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.

The menu ID needed for this can be found in the account portal

Copy the Keyword Menu ID

Example Code - Full CodePen Source
<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>
See this functionality in action

Initial Keyword Menu

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"
});
Example Code - Full CodePen Source
<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>
See the Keyword Menu preselected to a Category and Topic on load

Initial Select Options state

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.

Example Code - Full CodePen Source
<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>
See a live example of this

Adjusting Form Field Properties

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
});
Example Code - Full CodePen Source
<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>
See a live demo

Callbacks and further options

A few more loading parameters are worth knowing:

API

The createSlimUi() call returns a reference to a JS/TS api, which you can utilise to enrich your shop with more functionality.

Here you can find the TypeScript documentation of the whole API

Slim UI use cases

Following are some code examples of use cases that were inspired by our customers.

Switching to the Panel UI

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();
Example Code - Full CodePen Source
<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>
You can see a live example of this here

Enabling/Disabling options in a Select

You 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);
Example Code - Full CodePen Source
<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>
See a live example of this