Steps on your product page
A form laid out as steps (layout: 'steps', see
Page or steps) shows one group of the template at a
time. Your page can follow where it stands, and put its own fields and its
cart row inside the steps.
Where the form stands
Section titled “Where the form stands”While the generated form is shown as steps, the designer’s state carries
step, so onChange reports each move:
designer.getStep();// { index: 1, count: 3, groupId: 'message', isLast: false,// steps: [{ groupId: 'pet', label: 'Your pet' },// { groupId: 'message', label: 'Message' },// { groupId: 'sign', label: 'Sign' }] },// or undefined on a pagedesigner.setStep(0); // back to the first stepWhen the template lets customers add layers of their own, the last step is
the one they add them in, after the template’s groups. Its groupId is
$added.
index counts from 0 among the steps the form shows, and count is how many
there are; isLast is index === count - 1, the last step: the place to
show your own finishing button. steps names each of them in order, as their headings
read, for a stepper of your own beside the form’s. setStep(index) moves to a step, and is ignored on a
page or for an index that names no step. On a page, and with showForm: false
(you draw your own form, so there is no step on screen), the state has no
step and setStep does nothing.
Your options and your cart in the steps
Section titled “Your options and your cart in the steps”A product page often has fields of its own beside the designer, such as a shop’s variation selects, and its own price, quantity and Add to cart. Two options draw them inside the steps, so the customer goes through one flow:
mount(el, { publishableKey, templateId, layout: 'steps', optionsStep: { content: document.querySelector('.variations') }, lastStepContent: document.querySelector('.cart'),});optionsStep adds a first step before the template’s. It holds the blank’s
colour and size picker and the print size picker, which are then no longer
drawn above the form, and after them content, your own element. Its
heading is title, or the form.step-options message (“Options”) without
one, and getStep() names it with the group id "$options". The step bar
counts it like any other step. With no picker drawn and no content, there
is no Options step. The view switcher is not part of it: it stays above the
form, or in viewsTarget when you pass one.
lastStepContent is shown on the last step only, under Back. Watch the
step event (or isLast in getStep()) if your page needs to know when it
is shown.
Both elements are moved into the designer as they are, never copied, so
the listeners on them and on the controls in them keep working, and
destroy() puts each back where it was. A control moved out of the
<form> around it, such as a variation select taken from your cart form,
stays that form’s: the designer ties it to the form with its form
attribute (giving the form an id if it has none), so its value is still
submitted with the form, and takes the tie off again on destroy(). A
handler delegated from an ancestor, such as one listening on the cart form
for a change in its selects, is no longer reached while the element is in
the designer: listen on the element you pass, or on its controls. Pass
elements from elsewhere in your page, not from inside the elements the
designer is drawn into, which it empties. On a page, the options block opens the form,
above the first numbered group and with no heading of its own, and
lastStepContent ends it. Without either option, the form is drawn as it
always was.
Arranging the form’s groups
Section titled “Arranging the form’s groups”formGroups lays the template’s groups out for your page, without changing
the template: which groups are shown and in what order, which fields each
holds, your own elements placed among them, and the words they show. It
works in both layouts: a group is a step, or a numbered heading on a page.
const d = await mount(el, { publishableKey, templateId, layout: 'steps', formGroups: { groups: [ { id: 'shirt', title: 'Your shirt', items: [ { host: 'size', element: document.querySelector('#pa_size') }, { field: 'name:content', label: 'Name on the back', placeholder: 'Your name' }, { field: 'name:fontFamily', options: { Georgia: 'Classic' } }, ], }, ], },});document.querySelector('#pa_size').addEventListener('change', (e) => d.setHostItemComplete('size', e.target.value !== ''),);- A group’s
idis a template group’s, asgetFormSchema()names it, or a new one for a group of your own, which needs atitle.titlereplaces the group’s heading. - A field item names a field as
"<layerId>:<prop>", fromgetFormSchema(). Itslabel,help,placeholderandoptions(an offered value’s words, by the value) replace the template’s for this mount, in every language, andgetFieldTexts()uses them too. - A host item,
{ host, element }, moveselementinto the group, asoptionsStep’scontentis moved: never copied, put back ondestroy(), and with the same caveat about handlers delegated from an ancestor. - In the steps layout, Next waits on a step until each host item in it is
marked complete with
setHostItemComplete(id, true);falseholds Next again. On a page nothing waits.
Groups and fields you do not name are still shown, after yours, in the
template’s order, so a template that later gains a group or a field keeps
working. A field you name leaves its own group; a template group left with
nothing to show is left out. An id the template does not have is passed
over, with a console warning, and a malformed formGroups fails the mount
with a TypeError. A host item takes over from optionsStep: the pickers
are then drawn above the form. The step event and getStep() keep their
shape, naming each group by its id.
Questions? Write to [email protected].