Store forms
Render published store forms from the theme SDK, including custom layouts, steps, files, and the contact wrapper.
On this page
Store forms are published definitions that belong to the store. A theme renders them through
@poltura/theme-sdk/forms. The definition decides the field
types, steps, conditions and success message. The theme decides only how the form looks.
Render a form
import { StoreForm } from '@poltura/theme-sdk/forms';
export function Contact() {
return <StoreForm handle='contact' />;
}<StoreForm handle='contact' /> loads the published form and renders its visible fields,
steps, captcha, send button and success message. Its props shape the presentation without
changing the definition:
| Prop | What it does |
|---|---|
layout | stacked, or compact for two fields per row on wide screens |
appearance | default, muted, outline, inverse, in the theme's colours and fonts |
chrome | full draws the title, description and card; fields draws only the fields |
copy | The theme's own wording for the title, button, success message and each field's label and placeholder |
fieldVisibility | Fields to hide or show by field id, over the merchant's settings |
emailHints | Deliverability hints under email fields; a domain that takes no mail blocks send |
onAccepted | Called with the submission id once the store accepts it, and preview (true in the Customizer) |
Pass children for a custom layout. FormField draws one field with its label, control, help and
error (nothing while a condition hides it), and SubmitButton is the send button, which moves to
the next step on multi-step forms:
import { FormField, StoreForm, SubmitButton } from '@poltura/theme-sdk/forms';
export function Quote() {
return (
<StoreForm handle='quote' layout='compact' appearance='muted'>
<FormField id='name' />
<FormField id='email' />
<FormField id='attachments' />
<SubmitButton>Request a quote</SubmitButton>
</StoreForm>
);
}FormField also takes a render function for custom markup. It keeps validation, errors and the
aria-invalid and aria-describedby wiring. FieldControl is the platform control to place
inside it:
import { FieldControl, FormField } from '@poltura/theme-sdk/forms';
export function FramedMessage() {
return (
<FormField id='message'>
{(state) => (
<div className='rounded border p-3'>
<FieldControl
field={state.field}
value={state.value}
error={state.error}
onChange={state.setValue}
/>
</div>
)}
</FormField>
);
}For markup that is entirely your own, two hooks read the state inside a StoreForm.
useStoreForm() returns the whole form (status, values, errors, current step, submit, next,
back), and useStoreFormField('email') returns one field with its value, error, visibility and
setter.
Newsletter
NewsletterForm and NewsletterTrigger from @poltura/theme-sdk/forms render the newsletter
sign-up. useNewsletter() reads whether the store takes sign-ups, whether they must confirm by
email, and the wording to ask with. In a footer, the newsletter block (or
<NewsletterForm layout='footer' /> in a section of your own) draws the footer column. Every
newsletter form uses the store's published newsletter form and follows the store-wide newsletter
setting, so the consent wording and validation are the same everywhere.
Contact wrapper
ContactForm from @poltura/theme-sdk/forms renders <StoreForm handle='contact' />, the
store's published contact form, with wording props (formTitle, nameLabel, showName,
showSubject, submitLabel and more) for the theme's own copy. The platform contact-form block
passes its settings through to it.
The store must have a published form with the handle contact. The storefront never creates
one.
Customizer
Merchants add a Form section (store-form) on any template and choose a published form by
its name. The form owns its fields, translations and delivery. The section owns its presentation.
One form can be used in several places.
| Setting | What it does |
|---|---|
handle | The published form, chosen by name; its stable id in code |
layout | stacked or compact |
appearance | default, muted, outline, inverse, in the theme's colours |
width | compact, standard, wide |
placement | inline, popup, or right-side drawer |
trigger | click by default; automatic opens it after a delay |
button_label | Text on the button that opens the popup or panel |
popup_delay_seconds | Delay before it opens automatically; at least five seconds |
popup_frequency | once, session, or every 30 days |
Automatic opening is off in the Customizer and on checkout pages. Use the preview button to test the popup there. Buttons that open the form still work. Popups and panels scroll inside the viewport, keep keyboard focus inside, close with Escape or the close button, and return focus to the button that opened them. Closing and reopening the same form keeps what the shopper typed. Navigating away or opening a different form clears it. Nothing typed is saved in browser storage.
Attach a form to a button
In the Customizer, click a link or button on the canvas to select the section or block it belongs to, or select it in the section tree. Its link setting offers Open link and Open form. Choose a published form, a popup or right side panel, and a width. Preview form tries it without publishing the theme, and publishing the theme puts it live. Hold Alt (Option on a Mac) while you click the canvas to follow the link instead of selecting it. Form controls on the canvas stay usable.
Every url and link setting and every link list entry offers the same choice. A button written
in code is only editable in the Customizer if it reads a link setting. Do not attach form actions
to checkout or add-to-cart buttons.
import { FormTrigger, useFormActions } from '@poltura/theme-sdk/forms';
import { Link } from '@poltura/theme-sdk/routing';
import type { LinkValue } from '@poltura/theme-sdk/elements';
export function AskButton() {
return (
<FormTrigger handle='contact' display='drawer' width='standard'>
Ask a question
</FormTrigger>
);
}
export function SettingLink({ link }: { link: LinkValue }) {
return <Link href={link} className='underline' />;
}
export function QuoteButton() {
const { openForm } = useFormActions();
return (
<button
type='button'
onClick={(event) => openForm({ handle: 'quote', display: 'drawer' }, event.currentTarget)}
>
Request a quote
</button>
);
}Link from @poltura/theme-sdk/routing renders a link setting's value as it is. When the
merchant chose Open form, the stored href is a validated #poltura-form?… action, and
following it opens the form over the page without navigating. Ordinary links navigate as usual.
The platform supplies the form provider, so a theme does not mount one.
Initial rendering
The server loads the contact and newsletter forms ahead of time, and every form that a visible
store-form section or a link setting anywhere in the theme names (up to 32 different forms).
The first markup then contains the form instead of "Loading form". FormTrigger also starts
loading its form when it gets focus or the pointer moves over it. A handle that only code names
loads on demand. Call useFormActions().preloadForm(handle) to start loading it early, or expose
it through a link setting so the server loads it. Only published forms load this way, never a
draft.
Files
FormField and FieldControl handle file fields for you. A theme that draws its own file
control calls useStoreForm().uploadFiles(fieldId, files) and reads the picked files from
useStoreForm().files. Uploads go through the storefront, and the submitted value holds upload
ids, never file URLs.
In the Customizer preview, picked files stay in the browser and are not uploaded. A preview submission is sent as a preview, carries no files and is not stored.
Where definitions come from
Theme code never defines a form's fields. Merchants create and edit forms on the admin's Forms page, and the storefront reads only what they publish.
Captcha
Each published form has its own captcha setting, on unless the merchant turned it off under
Forms > Appearance in the admin and published the form. The server enforces the published
setting whatever the browser sends. StoreForm draws the captcha itself.
Next
- Theme assets and media: ship images and fonts with the theme.
- forms reference: every export of
@poltura/theme-sdk/forms.