Store Builder

Forms

Build a form in its own builder, collect submissions in one place, and sell with an order form — including ordering the whole cart.

Drag Form from the palette's Input group (vi: Nhập liệu) onto the page. The panel that opens has two tabs:

Ready-made — Contact, Subscribe, Consultation, Feedback & review, Event sign-up, Quote request, Job application, Full address, Order, Checkout (cart), two booking forms (they need the Booking app), the account forms, or Create a new form — a dialog asks for a name and a type, and you start from nothing; the form you made then heads the This site's forms tab. This site's forms — place a form the site already has, on another page or a second time.

Every card can be clicked, not only dragged: the form lands in the container you have selected, or at the end of the page in a section of its own when nothing is. Dragging places it exactly where you drop. A ready-made form is created on the server the moment it lands, so the box reads "not linked" for a beat before its fields arrive — that is not a failure.

A form belongs to the site, not to a page. Put it on three pages and all three feed one inbox, and one edit changes all three.

On the page, the whole form is one element. Clicking any of its fields selects the form — that is what you drag, resize and give a background; the Layer tree lists it as one row too. Individual fields are edited only in the form builder.

The form builder

Double-click the form on the canvas, or select it and press Edit form. A large dialog opens over the editor — a builder of its own that knows only about fields and rows, so dragging is much tighter. The rail on the left has six entries: Fields · Steps · Rules · Settings · Preview · Submissions.

A strip under the title is the form's checklist, and it updates as you edit — you learn what is wrong before you press Save, not after. Each item is one sentence naming the problem, and most come with the fix: Add inserts the missing field (a Review form needs a rating field, Login needs an email and a password, an Order needs a contact field so you know who ordered), Add Send button when the form has no way to be sent, Open Settings when an order form has no product chosen.

There are two kinds of item, and the line between them is simple: whatever the server would refuse blocks Save, everything else is a reminder. A missing required field, two fields writing to the same place or sharing a Field ID, a field linked to data this type of form does not allow — those grey out Save. No Send button, or email notifications on with no verified address — those still save, but the form will not do what you think, so the list says so. You can Cancel at any time, so you are never trapped.

  • Drag by the handle ⠿ or by the field body — the body only starts a drag after a few pixels, so a click is still just a click.
  • The drop target is a ghost the exact size the field will take. Drop on the top or bottom half of a field to go above or below it; drop on the left or right third to split that row into two or three columns. Nowhere valid means nothing is drawn.
  • On the Phone size a two-column row stacks — that is the default, and for a row built on desktop it stays that way. To put two fields side by side on the phone, switch to the Phone size and drag one field beside the other: the row you just made lays out horizontally there, and desktop is untouched. Dragging another field into a row that already exists leaves that row's layout alone; change it with ⌘↑ to select the row, then Layout → Direction.
  • The selected field has two grips on its edges — drag to change the column ratio, snapping to a 12-part grid.
  • ⌘↑ selects the parent. From a field in a row that is the row itself — it has its own toolbar, and the column ratio and the row's gap live there.
  • The eye button on the toolbar hides a field at the breakpoint you are viewing. In the builder it stays put and dims — if it vanished, there would be nothing to click to bring it back. In Preview and on the real page it is genuinely gone.
  • Click a field and the inspector on the right shows its content. General is what the shopper sees (label, placeholder, required…). Advanced opens with the Field ID — the column name in exports and the key every integration uses — then how the field must be answered, spacing, per-breakpoint visibility, and a Class box for anyone writing their own CSS. Anything that needs explaining has a ? beside its label.

Worth knowing:

  • Text fields have an Input type: Text · Email · Phone · Link. It changes the phone keyboard, and for Email/Link the server refuses a badly formed answer — not just the browser. Phone is deliberately not checked: a valid number looks different in every country, and refusing a real one costs an order.
  • If you do want phone numbers checked, ask for it: the Format row in Advanced offers Phone number, and a Countries row appears under it — pick one or several. A number passes when it fits any chosen country, written with its +code (+84912…) or in the national form (0912…); any other country is refused, so choose only the countries you actually sell to. With no country chosen the row checks nothing. The same row offers Digits only, Letters only, Postal code, and Custom for anyone writing their own expression.
  • Choice fields (radio, checkbox, select) edit their options in place; Bulk edit opens a sheet to paste one option per line — up to 100. Radio and checkbox lay out in 1–3 columns.
  • Choice fields can also fill their options from the store instead of typing them: the Source row (vi: Nguồn) offers Typed by hand, Products, Collections, Articles, Brands and Product tags. Brands lists the brands of the products the page shows; Product tags lists each tag of those products once — tags are split and de-duplicated, so if one product has New, Sale and another has New, you get two options, not three. Articles now lists your real articles on the published page, not just on the canvas.
  • The file field accepts several file types at once (Image, Video, PDF).
  • A group with a switch in its header (Icon, Character limit…) is collapsed: turn it on to see what is inside.

Save saves and closes; Cancel, Esc or clicking outside all ask first if there are unsaved changes. There is no third door that saves for you. ⌘ Z undoes inside the dialog.

The format an answer has to take

A text field's Advanced tab has a Format group:

No check · Digits only · Letters only · Vietnamese phone number · Postal code · Custom

This is not a second opinion on email — Input type already covers email and links. This group is where the rules the platform refuses to set for you live: you switch one on when you, not we, know what a wrong refusal costs. That is why there is a Vietnamese phone number entry and no generic "phone": a phone rule is only usable when it says which country it is for.

Three things to know:

  • The server checks again. The browser checks so the shopper can fix it on the spot — "This is not the format this field takes" beside the box — but the page is where a shopper can edit anything, so a wrong answer is refused a second time server-side. A rule set here is a real rule, not a reminder.
  • A rule only runs when there is something to check: an empty box is not "badly formatted". Whether an answer is required is still the Required switch — two different things that add up.
  • Format only speaks about the shape of an answer. Rules that belong to your shop — "book at least two hours ahead" — are written in your own code: see Hooking your code into a form.

Writing your own expression

Choose Custom and an Expression box appears, taking a regex you write.

It is not anchored for you. The four built-ins are anchored at both ends, so "Digits only" really is digits only. Yours stays exactly as written — and an unanchored regex only has to match somewhere inside, so [0-9]+ lets abc123 through. To match the whole answer write ^[0-9]+$.

It runs on two different engines: the shopper's browser uses JavaScript's regex, the server uses RE2 — no lookahead (?=…), no back-references \1. An expression only one side understands is a silent box that never matches, so it is stopped in two places: the inspector reports "This expression is not valid, so it is not being used" as you type, and Save refuses if the server cannot compile it.

It is not a security fence. Format catches honest typos; it does not stop anyone determined.

Steps

A long form can be split into steps, each a page of questions. Open Steps on the rail and press Add step.

The thing to know first: in the builder every step is drawn as its own card, but the published page has ONE box — the shopper walks through the steps in place. The cards show you the boundaries, not the layout the shopper gets.

Three things happen on their own, because a half-split form is an unusable one:

  • The first step wraps everything the form already has into Step 1. A field outside every step still shows on the page, but nobody collects its answer.
  • Every step gets its own Back / Next bar at its end. Each bar carries every button; the published page hides the ones that step's position does not use (no Back on the first, no Next on the last).
  • The send button always follows the last step, inside that step's bar. Reorder the steps and it moves; delete the step holding it and it moves to the new last step.

Deleting a step takes its questions with it — the dialog says how many before you decide.

Styling the buttons themselves

Back, Next and the step counter are three separate elements. Click a button on the canvas and the inspector opens on it: text, colours, border, corners, padding, width, font size, an icon.

Four oddities, each with a reason:

  • The two buttons cannot be deleted. A step without Next is a step the shopper cannot leave, and on the canvas you cannot tell — the published page already hides the button a step does not use, so a deleted button looks exactly like a correctly hidden one.
  • The counter is turned off with the eye, not deleted — deleted, there is no way to put it back, since nothing can be dropped into the bar.
  • Draggable, but only within its own bar. The ⠿ handle reorders within the row; to flip the whole row, select the bar and change Layout → Direction. Drag a button's right grip to change its width.
  • A button the step does not use dims rather than disappears — still clickable, still styleable. If it were hidden outright, step 1's Back would be the one button you could never style, and it would appear unstyled the moment you added a step in front.

A new step arrives styled like the bar you already made — only the text is left blank, since each step gets to say its own words. The counter shows the real number ("1/3") right in the builder.

One form in several places

Same steps, two ways to reach the shopper, chosen as you drag the form onto the page. A stepped form shows two cards in the palette:

  • One box, walked through step by step — a single box, the shopper presses Next.
  • N separate blocks, placed anywhere — each step its own box, scattered across the page. No Back / Next, because everything is already showing.

A form without steps shows one card.

There is still only ONE send button, and it collects the answers from every block on the page. The button in the last box still gets what the shopper typed in the first. That is also why a missing required answer is reported where it sits — the only place the shopper can answer it.

Three separate boxes look exactly like three different forms, so click one block and every block of the same form lights up, each wearing the form's name.

Three traps, all of them silent if nobody says so first

  • The block holding the send button has to be placed. Forget it and the page shows a form that looks complete and cannot send. The builder warns under the picker when no block on the page can carry the send button.
  • Do not place a step twice. The picker marks placed steps (already on this page), and a second box lands on the next free step.
  • Adding steps AFTER the form is on the page is something the palette cannot help with. Select a block and the inspector says "2 more steps are not on this page" with a Place them button: the missing blocks land beside the one you selected.

To change your mind about a placed box: select it and, in the inspector's Step row, switch between The whole form and Step 1 / Step 2 / ….

Rules run across blocks: a rule can hide a question that sits in another box.

Conditional rules

Rules on the rail answers the question a twenty-field form actually raises: what rules does this form have? A rule reads as one sentence — If … Then …:

  • The If part chains several conditions with And / Or.
  • The Then part targets several fields at once, each getting one of four outcomes: hidden, shown, optional, required.

A rule belongs to the form, not to a field. Open a rule and the fields it mentions are outlined on the form and tagged If / Then.

Three surprises:

  • Rules are enforced on the server too. A field a rule hides is not checked for "required" and stores no answer; a field a rule makes required stays required, even if somebody edits the page in their browser.
  • A hidden field is never required, whatever a rule says. A required field the shopper cannot see is a form that refuses to send and cannot say why.
  • The later rule wins. Two rules aiming at one field: the lower one decides.

Drag Email out of the Contact group and the field is already linked to the customer record — a submission creates or updates the row under Manage → Customers. The Contact group is the linking; there is nothing to configure.

A Custom form keeps no customer, so dragging the first Contact field into a Custom form switches it to a Contact form by itself, saying so:

Switched to a Contact form so customer details are saved

Removing that field again keeps the Contact type — changing it back is yours to do, in Settings, which always opens with the form's type and one sentence on what it does. A linked field shows Saves to: … in the inspector, beside Unlink. Rows that cannot link on the current type (payment or shipping fields on a form that is not an order) are shown disabled with the reason, rather than letting you drag them in and failing at save.

Every field has an ID in the inspector. For the login/register forms the ID is how the system recognises which field is the email and which the password — rename those IDs and login breaks, and the builder names the missing field in the checklist, before you save.

Address: several boxes, one address

The Contact group has eight address rows. Seven are single boxes — Country, Province / City, Ward, District, Street address, Building, floor, unit, Postal code — and one is a pair, Province + Ward (one row), which drops two selects side by side.

District is the third administrative level, for countries that have one (Thailand has tambon inside amphoe); Vietnam has had two levels since 2025-07-01. So it is a row you drag in when you need it.

Take only the boxes you need: a shop delivering in one city may use ward and street alone; a shop posting parcels adds the postal code. Each box is its own field, so it goes anywhere, at any width, in any step.

The boundary data is the platform's: Vietnam follows the two-level model province → ward, no district, and the platform knows sixty-four other countries. A shopper cannot type a ward that does not exist, so the address columns in your orders are normalised data.

Other countries' boundaries are loaded on request. For a country not yet loaded, the province box turns into a text box — the shopper can still send, and the inspector says so the moment you pick the country. Exception: a box with Sell only to set never accepts free text, because it would silently widen the area you just narrowed.

Each box is its own answer

Submissions and the Excel export have one column per box, not one combined address line. The combined line lives where it is actually needed: Manage → Customers, beside separate province, ward and postal-code columns for filtering.

The province and ward boxes store the name, with the code beside it: the table shows "Hồ Chí Minh", the code is kept for reports to group by. The server looks the name up from the code; the page never writes it.

Every box tells the browser which part of an address it is, so a shopper with a saved address gets the whole set filled in at once — the two selects included.

Which boxes belong to one address

Click an address box on the canvas and every box of the same address lights up. In the inspector each box has a Linked switch: on (default) means the box belongs to an address — ward follows province, the street box suggests streets for that province; off means it stands alone, for a "which province are you in" question without the rest.

Off on a ward box means the box cannot open — it has no province to follow. The builder says so right under the switch.

Until a province is chosen, the ward box reads "Choose a province first" rather than sitting there greyed out.

When a form has two addresses

A form asking for both a delivery and a billing address has two addresses. Then — and only then — the inspector shows an Address row: this box belongs to Address 1, Address 2, or + New address.

If one address has two province boxes, its ward box does not guess: it stays shut until you sort it out. A box that will not open is a question you can see; a ward list for the wrong city is an order delivered to the wrong city that nobody goes looking for.

Start somewhere, and sell only where you deliver

Every box with a list has two more rows:

  • Preselect — the box opens already on one place; the shopper can change it.
  • Sell only to — choose several places, and the box offers only those. Empty means everywhere.

Preselect says "start here"; sell only to says "I do not deliver anywhere else".

Choose exactly one place and the box fills itself in — a list with one option is no longer a question. It is also the shortest way to say "this shop sells in Vietnam only": the Country box → Sell only to → Vietnam.

This is a real rule. The server checks on submit: a province outside the list is refused with "We don't deliver to this area yet", even if somebody edits the page in their browser.

A lower box can only be limited once the box above is fixed. To say "only these four wards", the province above must be preselected or limited to one — if the shopper chooses the province, there is no one ward list to choose from. The inspector says so instead of handing you an empty box.

The Postal code box also has a Country row, because the code is checked per country — Thai codes have 5 digits, Vietnamese 6. Once the address has a Country box, that row disappears from every box: the country is then the shopper's answer, not your setting.

Several countries in one form

Drag the Country row in and the province box below follows it: switch to Thailand and the province list changes, the ward follows, the postal code is checked against that country. Without a Country box, each box says which country's address it collects in its Country row — Vietnam by default.

"Same as the delivery address"

Drag the Same as another address row in and one tick answers the whole second address. It declares two things: Address says which address the answer lands in, Copy from says which it comes from. Ticked by default is on — right for nearly everyone; the rest untick and the boxes appear.

The copy is done by the SERVER, before anything is checked. Every rule still applies to the copied answers. And a tick does not conjure an address: if the delivery address is empty, so is the billing one, and the form reports the gap on the delivery boxes.

Boxes match by kind: province to province, ward to ward; a box missing on either side is skipped.

Street suggestions

The street box suggests street names as the shopper types, from the platform's own street list, filtered to the province just chosen. Unaccented typing works: nguyen hu finds Nguyễn Huệ, Nguyễn Hữu Cảnh. The list lives on the platform, so it depends on no outside service. Under the suggestions sits © OpenStreetMap contributors — the credit the data licence requires; clicking it selects nothing.

A street not in the list is simply typed, with no error — a red line under an address box makes people doubt a perfectly good address.

Old forms keep working. The address used to be one field drawing three boxes; forms you already made keep that field. To move to separate boxes, delete the old field and drag the new rows in.

Order forms: a pinned product, or the whole cart

Two ready-made forms for two ways of selling, and picking the wrong one is a silent error:

  • Order — sells exactly one product you pin. Has a quantity box. Right for a page presenting one product.
  • Checkout (cart) — sells the shopper's whole cart: no quantity box (each cart line carries its own) and a Payment method field built in. This is the form for the Checkout page.

In Settings, Order source switches between the two: Pinned product or Shopper's cart. With the cart, prices always come from your catalogue at the moment of ordering; if a product in the cart has been withdrawn, the whole order is refused and the shopper is told which one. The cart empties after a successful order.

Both routes create a real order under Manage → Orders, with the site's automatic discounts applied.

Asking how they pay and how it arrives

The palette's Basic group has two rows wired to the right order columns: Payment method and Shipping method. Use them rather than a plain select, because that wiring has no inspector box to set by hand.

Payment method drops one card per way to pay — Cash on delivery first, then every gateway you have enabled under Apps → Payments. Each card's name and description are editable; the small code under it (cod, vnpay…) is what the server matches, so it is not. Add method offers only gateways the shop actually accepts — to add a new way to pay, connect the gateway first.

The Logos group in the inspector puts each gateway's official mark on its card — VNPay, MoMo, PayOS, ZaloPay, SePay, PayPal, Stripe, taken from the brands' own asset sets; the PayPal and Stripe marks are used exactly as their brand kits ship them, per both brands' no-modification terms. The group is on by default for a new card; a card you placed earlier keeps whatever it was set to, so a page already published does not change on its own. Logo height is set per breakpoint, so the mark on a phone can be smaller than on a desktop.

Logo shape chooses between As published and Square. The part worth knowing first: five of the seven brands publish a square mark of their own (VNPay, MoMo, payOS, PayPal, Stripe) and ZaloPay and SePay do not — neither publishes one anywhere, and cropping a wide mark into a square would be inventing a logo on their behalf. So in Square those two still draw their wide mark, made smaller to fit the square slot. The inspector says so out loud, naming the cards it cannot square, rather than leaving you to work out why the row still looks uneven.

The fix for those two — and for the Cash on delivery card — is to set a logo on the method itself: click the logo box at the start of each row in Option list and pick an image from the library. Your image beats the brand's. It is also the only way a way to pay that is not a gateway can carry a mark at all, because there is no brand to fetch one from: cash at the counter, or a transfer you reconcile yourself. Clear the image and the card goes back to the brand's mark.

Shipping method fills its options from Settings → Shipping the moment you drop it, and the server matches the name the shopper picked against that list to work out the fee. Three things to know:

  • With no methods declared, the select drops in empty. Declare first, drag second.
  • Editing the option text by hand is the surest way to break the fee: an option not in the settings list is charged 0.
  • Remove a method from the settings and new orders stop being charged for it; existing orders keep the fee they were charged.

Quantity and the order note

Also under Basic: Quantity (minimum 1) and Order note (a multi-line box). Order note is not the Contact group's Note: Note is what the shop should know about that person and stays on the customer record; Order note is about this order — "deliver after 6pm" — and is read beside the line items.

Submissions

The Submissions tab lists every submission, one column per field, with an Excel export. The same data is under Manage → Forms.

The search box above the table looks through every answer — a name, an email, a phone number — and ignores accents: van an finds Nguyễn Văn An. The same search runs from the ⌘K box anywhere in Manage: type what the customer typed, the results show the matching answer with the form's name beside it, and choosing one opens that form with the table already filtered — because what you remember is the customer, not which form took the answer.

In Settings: Email me new responses sends each submission to the addresses you add — an address only receives once someone opens the verification link sent to it. A new form notifies the site owner by default, and the owner's email counts as verified because the account already proved it at sign-up; any other address still goes through the link. Don't keep responses is for a form whose answers already go somewhere else.

Unread, and the bell

A new response is bold with a dot until you open it. The forms list has a New column, the Forms entry in the sidebar counts the site's unread total, and the bell in the top bar has one line per form with new responses — including on other sites you belong to. Read them and the line goes away by itself; there is nothing separate to "mark as seen". A response's detail has Mark as unread to save it for later, and the status filter has Unread.

A response caught as spam never counts as unread — if it did, one wave of spam would make the bell meaningless.

Edited the form, but the published page still has the old one

A published page keeps the version of the form it was published with. Change a question, add a field or change where visitors go, and visitors keep seeing the old one until the page is published again. After you save, the builder (and the form's screen in Manage) says so:

This form is on N published pages with an older version — Republish these pages

That button republishes from each page's published version, not from its draft — so whatever you are halfway through on the page does not go live along with the form.

Where the visitor goes after sending

After sending in Settings offers two choices: Show a thank-you message (the message replaces the form) or Go to another page — A page of this site, or An external link such as the shop's Zalo or Facebook page. Switching back and forth keeps the thank-you text you wrote.

The trap: the link to a page of your site is fixed when the page holding the form is published, not when a visitor sends it. So:

  • If the target page is still a draft, visitors see the thank-you message instead of being sent to a page that does not exist. Publish the target, then republish the page with the form.
  • The same holds when you later change the target's address: the form keeps sending visitors to the old one until you republish the page with the form.

An external link must be a full http:// or https:// link with a domain; anything else is refused when you save, because a link that runs code instead of opening a page is the classic way to turn a shop's form into a trap. An order form with a payment gateway still sends the visitor to pay first. Being sent elsewhere also means the visitor does not see their order or booking number on screen — the form's checklist points this out.

A confirmation email for the visitor

Send the visitor a confirmation email — The visitor gets an email confirming we received their info. It never echoes back their answers.

Off until you turn it on, per form. It exists on Contact and Subscribe forms only, and the form needs an Email box from the Contact group — the checklist says so straight away, because with no address there is nobody to send to. Order and booking forms already send their own emails.

The email never repeats the answers, on purpose: if it did, anybody could type someone else's address into your form and use the shop's name to send them whatever they liked. For the same reason:

  • Your Extra message goes out only once the site has its own email set up (Mail app). While the site sends from the platform's shared address, visitors get the thank-you line only.
  • Each address gets at most one confirmation per form per day, and a site at most 200 a day. A response past the limit is still stored like any other; only the email is skipped.
  • A submission caught as spam sends no email at all — neither yours nor the visitor's.

Where visitors came from

Each response records the visitor's traffic source: the utm_ parameters of an ad link (source, medium, campaign, term, content) and the referring site when they clicked through from another website. You see them in the Traffic source box when you open a response, in the Source column of the table, and as six columns in the Excel file. The Source filter above the table lists every source seen, with a count; (None) is the responses with no utm_source.

Three things to know when reading the numbers:

  • It is the first touch of a session: a visitor who arrives from a Facebook ad and browses three more pages before sending is still recorded as Facebook. Closing the tab ends the session. No cookie is used.
  • The referring site keeps only the domain and path and drops everything after the ?, because that part often carries someone's email or an id.
  • Responses sent before this feature existed carry no source and show —, not "direct" — nobody knows where those visitors came from.

Passwords

A password field is never stored in a submission, even if somebody attaches one to an ordinary form. The account forms (login, register…) are covered in Customer accounts.

Updated 10/10/2026