Migrate Form Layout from Polaris React
Replace Polaris React FormLayout and FormLayout.Group with s-grid. s-grid controls layout only. Keep form submission on a native form element, and keep labels, values, validation, and errors on each field.
Anchor to Migrate a form layoutMigrate a form layout
The following example preserves a two-column name group that collapses to one column when its container is 500 pixels wide or narrower. The email field remains a full-width row.
Migrating a contact form layout
Polaris web components
function MerchantContactForm() {
return (
<form data-save-bar>
<s-grid gridTemplateColumns="1fr" gap="base">
<s-query-container>
<s-grid
gridTemplateColumns="@container (inline-size > 500px) 1fr 1fr, 1fr"
gap="base"
>
<s-text-field
label="First name"
name="firstName"
autocomplete="given-name"
/>
<s-text-field
label="Last name"
name="lastName"
autocomplete="family-name"
/>
</s-grid>
</s-query-container>
<s-email-field
label="Email"
name="email"
autocomplete="email"
/>
</s-grid>
</form>
);
}Polaris React
import {FormLayout, TextField} from '@shopify/polaris';
import {useState} from 'react';
export function MerchantContactForm() {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [email, setEmail] = useState('');
return (
<FormLayout>
<FormLayout.Group>
<TextField
label="First name"
value={firstName}
onChange={setFirstName}
autoComplete="given-name"
/>
<TextField
label="Last name"
value={lastName}
onChange={setLastName}
autoComplete="family-name"
/>
</FormLayout.Group>
<TextField
label="Email"
type="email"
value={email}
onChange={setEmail}
autoComplete="email"
/>
</FormLayout>
);
}Preview
The migrated fields use name attributes so that the native form includes their values in FormData. The example also adds data-save-bar so that the form participates in the App Bridge save-bar pattern. Omit data-save-bar if the form doesn't track unsaved changes.
| Polaris React | Polaris web components | Migration notes |
|---|---|---|
FormLayout | An outer s-grid with gridTemplateColumns="1fr" | Creates the vertical sequence of rows. |
FormLayout.Group | A nested s-grid | Creates columns for related fields. |
| Space between fields | gap | Choose a documented Polaris spacing value. |
| Responsive grouping | s-query-container and a container query in gridTemplateColumns | Base the field layout on the available container width, not the viewport width. |
condensed group | An explicit gridTemplateColumns value | Choose column widths for the form instead of carrying the visual preset forward. |
Group title | An s-heading before the nested grid | Keep the heading and fields together in the outer grid. |
Group helpText | An s-paragraph before the nested grid | Keep instructions visible and adjacent to the fields they describe. |
Don't replace FormLayout with s-stack. A grid expresses field columns and their responsive collapse without adding layout wrappers around each field.
Anchor to Preserve form behaviorPreserve form behavior
s-grid doesn't own form state. Migrate each field's behavior with the field component:
- Add a stable
nameto every value that the form submits. - Preserve
autocomplete, required state, constraints, and validation messages. - Preserve controlled state when app logic needs it. Use native form values when React doesn't need to own each keystroke.
- Keep source order aligned with the intended reading and keyboard order. CSS columns shouldn't reorder fields.
- Keep a group heading or instructions adjacent to the group instead of placing them in placeholder text.
For field-specific property mappings, refer to the migration guide for that field, such as TextField or Select.
Anchor to Test the migrationTest the migration
- Resize the form's container through each layout breakpoint, including when the app navigation changes the available width.
- Verify the reading and keyboard order in both the one-column and multi-column layouts.
- Submit the form, and confirm that
FormDatacontains every named field. - Verify field errors and instructions remain associated with the correct field.
- If you use
data-save-bar, then test save, discard, validation failure, and navigation with unsaved changes.
Anchor to Remove Polaris ReactRemove Polaris React
After every FormLayout call site is migrated, remove the FormLayout import and layout wrappers used only by it. Remove @shopify/polaris only after no other route in scope imports it.