Version 2025-07 is the last API version to support React-based UI components. Later versions use web components, native UI elements with built-in accessibility, better performance, and consistent styling with Shopify's design system. Check out the migration guide to upgrade your extension.
FunctionSettings
The FunctionSettings component configures metafield settings for Shopify Functions. Use FunctionSettings to create configuration interfaces that allow merchants to customize function behavior through structured input fields and controls.
This component provides a standardized layout for settings forms and integrates with the native save bar to handle form submission. For general form submission, use Form.
Supported targets
- admin.
abandoned-checkout-details. action. render - admin.
abandoned-checkout-details. block. render - admin.
catalog-details. action. render - admin.
catalog-details. block. render - admin.
collection-details. action. render - admin.
collection-details. block. render - admin.
collection-index. action. render - admin.
company-details. action. render - admin.
company-details. block. render - admin.
company-location-details. block. render - admin.
customer-details. action. render - admin.
customer-details. block. render - admin.
customer-index. action. render - admin.
customer-index. selection-action. render - admin.
customer-segment-details. action. render - admin.
discount-details. action. render - admin.
discount-details. function-settings. render - admin.
discount-index. action. render - admin.
draft-order-details. action. render - admin.
draft-order-details. block. render - admin.
draft-order-index. action. render - admin.
draft-order-index. selection-action. render - admin.
gift-card-details. action. render - admin.
gift-card-details. block. render - admin.
order-details. action. render - admin.
order-details. block. render - admin.
order-details. print-action. render - admin.
order-fulfilled-card. action. render - admin.
order-index. action. render - admin.
order-index. selection-action. render - admin.
order-index. selection-print-action. render - admin.
product-details. action. render - admin.
product-details. block. render - admin.
product-details. configuration. render - admin.
product-details. print-action. render - admin.
product-details. reorder. render - admin.
product-index. action. render - admin.
product-index. selection-action. render - admin.
product-index. selection-print-action. render - admin.
product-purchase-option. action. render - admin.
product-variant-details. action. render - admin.
product-variant-details. block. render - admin.
product-variant-details. configuration. render - admin.
product-variant-purchase-option. action. render - admin.
settings. order-routing-rule. render - admin.
settings. validation. render
Supported targets
- admin.
abandoned-checkout-details. action. render - admin.
abandoned-checkout-details. block. render - admin.
catalog-details. action. render - admin.
catalog-details. block. render - admin.
collection-details. action. render - admin.
collection-details. block. render - admin.
collection-index. action. render - admin.
company-details. action. render - admin.
company-details. block. render - admin.
company-location-details. block. render - admin.
customer-details. action. render - admin.
customer-details. block. render - admin.
customer-index. action. render - admin.
customer-index. selection-action. render - admin.
customer-segment-details. action. render - admin.
discount-details. action. render - admin.
discount-details. function-settings. render - admin.
discount-index. action. render - admin.
draft-order-details. action. render - admin.
draft-order-details. block. render - admin.
draft-order-index. action. render - admin.
draft-order-index. selection-action. render - admin.
gift-card-details. action. render - admin.
gift-card-details. block. render - admin.
order-details. action. render - admin.
order-details. block. render - admin.
order-details. print-action. render - admin.
order-fulfilled-card. action. render - admin.
order-index. action. render - admin.
order-index. selection-action. render - admin.
order-index. selection-print-action. render - admin.
product-details. action. render - admin.
product-details. block. render - admin.
product-details. configuration. render - admin.
product-details. print-action. render - admin.
product-details. reorder. render - admin.
product-index. action. render - admin.
product-index. selection-action. render - admin.
product-index. selection-print-action. render - admin.
product-purchase-option. action. render - admin.
product-variant-details. action. render - admin.
product-variant-details. block. render - admin.
product-variant-details. configuration. render - admin.
product-variant-purchase-option. action. render - admin.
settings. order-routing-rule. render - admin.
settings. validation. render
Anchor to PropertiesProperties
Props for the FunctionSettings component, a form container designed for Shopify Function configuration experiences. It provides hooks for saving settings and handling server-side validation errors.
- Anchor to idididstringstring
A unique identifier for the function settings form. Use this when you need to reference the form from elements outside its tree.
- Anchor to onErroronErroronError(errors: FunctionSettingsError[]) => void(errors: FunctionSettingsError[]) => void
A callback that fires when committing the saved changes to Shopify's servers fails. The
errorsarray only contains errors caused by data your extension provided. Network errors and other issues outside your control aren't reported here.Use this callback to highlight the fields that caused the errors and display the error messages to the merchant.
- Anchor to onSaveonSaveonSave() => void | Promise<void>() => void | Promise<void>
A callback that fires when the merchant saves their changes in the admin-rendered function settings experience. If you return a
Promise, then the Shopify admin waits for it to resolve before committing changes to Shopify's servers. If the promise rejects, then the Shopify admin aborts the save and displays an error using themessageproperty of the rejected value.
FunctionSettingsError
Describes an error that occurred when committing function settings to Shopify's servers. These errors are scoped to data the extension provided and can be displayed directly to the merchant.
- code
A machine-readable identifier for the category of error. These match GraphQL error codes as closely as possible. For example, the values returned by the `metafieldsSet` mutation. Learn more about the [MetafieldsSetUserErrorCode](/docs/api/admin-graphql/latest/enums/MetafieldsSetUserErrorCode) enum.
string - message
A human-readable, translated message describing the error. You can display this directly to the merchant.
string
Anchor to ExamplesExamples
Anchor to Configure function validation settingsConfigure function validation settings
Build a settings page for a Shopify Function that saves configuration as metafields. This example uses FunctionSettings with applyMetafieldsChange to save a validation rule name entered in a TextField.
Configure function validation settings
 that saves configuration as metafields. This example uses `FunctionSettings` with `applyMetafieldsChange` to save a validation rule name entered in a [TextField](/docs/api/admin-extensions/2025-07/ui-components/forms/textfield).](https://cdn.shopify.com/shopifycloud/shopify-dev/production/assets/assets/images/templated-apis-screenshots/admin-extensions/2025-07/form-default-CIQEVvTJ.png)
Configure function validation settings
React
import {useState} from 'react';
import {reactExtension, useApi, FunctionSettings, TextField, Section} from '@shopify/ui-extensions-react/admin';
export default reactExtension(
'admin.settings.validation.render',
async (api) => {
const initialSettings = api.data.validation
? await fetchSettings(api.data.validation.id)
: {};
return <App settings={initialSettings} />;
},
);
function App({settings}) {
const [name, setName] = useState(settings.name || '');
const [error, setError] = useState();
const {applyMetafieldsChange} = useApi();
return (
<FunctionSettings onError={(errors) => setError(errors[0]?.message)}>
<Section heading="Validation settings">
<TextField
label="Rule name"
name="name"
value={name}
error={error}
onChange={(value) => {
setName(value);
setError(undefined);
applyMetafieldsChange({
type: 'updateMetafield',
namespace: '$app:validation',
key: 'name',
value,
valueType: 'single_line_text_field',
});
}}
/>
</Section>
</FunctionSettings>
);
}TS
import {extension, FunctionSettings, TextField, Section} from '@shopify/ui-extensions/admin';
export default extension(
'admin.settings.validation.render',
async (root, api) => {
const initialSettings = api.data.validation
? await fetchSettings(api.data.validation.id)
: {};
const nameField = root.createComponent(TextField, {
value: initialSettings.name || '',
label: 'Rule name',
name: 'name',
onChange(value) {
nameField.updateProps({value, error: undefined});
api.applyMetafieldsChange({
type: 'updateMetafield',
namespace: '$app:validation',
key: 'name',
value,
valueType: 'single_line_text_field',
});
},
});
const section = root.createComponent(Section, {
heading: 'Validation settings',
});
const settings = root.createComponent(FunctionSettings, {
onError(errors) {
nameField.updateProps({error: errors[0]?.message});
},
});
section.appendChild(nameField);
settings.appendChild(section);
root.appendChild(settings);
},
);Anchor to Manage multiple metafield settingsManage multiple metafield settings
Collect multiple metafield values in a single settings form using NumberField and TextField components. This example manages minimum quantity, maximum quantity, and a custom error message, writing each change to its own metafield key through applyMetafieldsChange.
Manage multiple metafield settings
React
import {useState} from 'react';
import {reactExtension, useApi, FunctionSettings, TextField, NumberField, Section} from '@shopify/ui-extensions-react/admin';
export default reactExtension(
'admin.settings.validation.render',
async (api) => {
const initialSettings = api.data.validation
? await fetchSettings(api.data.validation.id)
: {};
return <App settings={initialSettings} />;
},
);
function App({settings}) {
const [min, setMin] = useState(settings.minQuantity || 1);
const [max, setMax] = useState(settings.maxQuantity || 100);
const [message, setMessage] = useState(settings.errorMessage || '');
const [error, setError] = useState();
const {applyMetafieldsChange} = useApi();
return (
<FunctionSettings onError={(errors) => setError(errors[0]?.message)}>
<Section heading="Quantity limits">
<NumberField
label="Minimum order quantity"
name="minQuantity"
min={1}
value={min}
error={error}
onChange={(value) => {
setMin(value);
applyMetafieldsChange({
type: 'updateMetafield',
namespace: '$app:validation',
key: 'min_quantity',
value: String(value),
valueType: 'number_integer',
});
}}
/>
<NumberField
label="Maximum order quantity"
name="maxQuantity"
min={1}
value={max}
onChange={(value) => {
setMax(value);
applyMetafieldsChange({
type: 'updateMetafield',
namespace: '$app:validation',
key: 'max_quantity',
value: String(value),
valueType: 'number_integer',
});
}}
/>
<TextField
label="Error message shown to customers"
name="errorMessage"
value={message}
onChange={(value) => {
setMessage(value);
applyMetafieldsChange({
type: 'updateMetafield',
namespace: '$app:validation',
key: 'error_message',
value,
valueType: 'single_line_text_field',
});
}}
/>
</Section>
</FunctionSettings>
);
}TS
import {extension, FunctionSettings, TextField, NumberField, Section} from '@shopify/ui-extensions/admin';
export default extension(
'admin.settings.validation.render',
async (root, api) => {
const initialSettings = api.data.validation
? await fetchSettings(api.data.validation.id)
: {};
const minField = root.createComponent(NumberField, {
value: initialSettings.minQuantity || 1,
label: 'Minimum order quantity',
name: 'minQuantity',
min: 1,
onChange(value) {
minField.updateProps({value});
api.applyMetafieldsChange({
type: 'updateMetafield',
namespace: '$app:validation',
key: 'min_quantity',
value: String(value),
valueType: 'number_integer',
});
},
});
const maxField = root.createComponent(NumberField, {
value: initialSettings.maxQuantity || 100,
label: 'Maximum order quantity',
name: 'maxQuantity',
min: 1,
onChange(value) {
maxField.updateProps({value});
api.applyMetafieldsChange({
type: 'updateMetafield',
namespace: '$app:validation',
key: 'max_quantity',
value: String(value),
valueType: 'number_integer',
});
},
});
const messageField = root.createComponent(TextField, {
value: initialSettings.errorMessage || '',
label: 'Error message shown to customers',
name: 'errorMessage',
onChange(value) {
messageField.updateProps({value});
api.applyMetafieldsChange({
type: 'updateMetafield',
namespace: '$app:validation',
key: 'error_message',
value,
valueType: 'single_line_text_field',
});
},
});
const section = root.createComponent(Section, {
heading: 'Quantity limits',
});
const settings = root.createComponent(FunctionSettings, {
onError(errors) {
const firstError = errors[0]?.message;
minField.updateProps({error: firstError});
},
});
section.appendChild(minField);
section.appendChild(maxField);
section.appendChild(messageField);
settings.appendChild(section);
root.appendChild(settings);
},
);Anchor to Validate settings on saveValidate settings on save
Use the onSave callback to notify your backend when the admin saves changes. This example configures a discount function with a title and type ChoiceList, calling your validation endpoint during save and surfacing any errors through onError.
Validate settings on save
React
import {useState} from 'react';
import {reactExtension, useApi, FunctionSettings, TextField, ChoiceList, Section, BlockStack} from '@shopify/ui-extensions-react/admin';
export default reactExtension(
'admin.settings.validation.render',
async (api) => {
const initialSettings = api.data.validation
? await fetchSettings(api.data.validation.id)
: {};
return <App settings={initialSettings} />;
},
);
function App({settings}) {
const [title, setTitle] = useState(settings.title || '');
const [type, setType] = useState(settings.type || 'percentage');
const [error, setError] = useState();
const {applyMetafieldsChange} = useApi();
return (
<FunctionSettings
onSave={async () => {
await fetch('/api/functions/validate-config', {method: 'POST'});
}}
onError={(errors) => setError(errors[0]?.message)}
>
<Section heading="Discount configuration">
<BlockStack gap>
<TextField
label="Discount title"
name="title"
required
value={title}
error={error}
onChange={(value) => {
setTitle(value);
setError(undefined);
applyMetafieldsChange({
type: 'updateMetafield',
namespace: '$app:discount',
key: 'title',
value,
valueType: 'single_line_text_field',
});
}}
/>
<ChoiceList
name="discountType"
value={type}
choices={[
{label: 'Percentage discount', id: 'percentage'},
{label: 'Fixed amount discount', id: 'fixed'},
]}
onChange={(value) => {
setType(value);
applyMetafieldsChange({
type: 'updateMetafield',
namespace: '$app:discount',
key: 'type',
value,
valueType: 'single_line_text_field',
});
}}
/>
</BlockStack>
</Section>
</FunctionSettings>
);
}TS
import {extension, FunctionSettings, TextField, ChoiceList, Section, BlockStack} from '@shopify/ui-extensions/admin';
export default extension(
'admin.settings.validation.render',
async (root, api) => {
const initialSettings = api.data.validation
? await fetchSettings(api.data.validation.id)
: {};
const titleField = root.createComponent(TextField, {
value: initialSettings.title || '',
label: 'Discount title',
name: 'title',
required: true,
onChange(value) {
titleField.updateProps({value, error: undefined});
api.applyMetafieldsChange({
type: 'updateMetafield',
namespace: '$app:discount',
key: 'title',
value,
valueType: 'single_line_text_field',
});
},
});
const typeChoice = root.createComponent(ChoiceList, {
name: 'discountType',
value: initialSettings.type || 'percentage',
choices: [
{label: 'Percentage discount', id: 'percentage'},
{label: 'Fixed amount discount', id: 'fixed'},
],
onChange(value) {
api.applyMetafieldsChange({
type: 'updateMetafield',
namespace: '$app:discount',
key: 'type',
value,
valueType: 'single_line_text_field',
});
},
});
const section = root.createComponent(Section, {
heading: 'Discount configuration',
});
const settings = root.createComponent(FunctionSettings, {
onSave: async () => {
await fetch('/api/functions/validate-config', {method: 'POST'});
},
onError(errors) {
titleField.updateProps({error: errors[0]?.message});
},
});
const content = root.createComponent(BlockStack, {gap: true});
content.appendChild(titleField);
content.appendChild(typeChoice);
section.appendChild(content);
settings.appendChild(section);
root.appendChild(settings);
},
);Anchor to Best practicesBest practices
Anchor to LimitationsLimitations
- FunctionSettings doesn't include a built-in reset callback like Form. The save bar's discard behavior is managed by the Shopify admin.
- FunctionSettings doesn't validate input values before save. You must implement your own validation logic and display errors on individual fields.
- Only one FunctionSettings component should be used per extension view. Each FunctionSettings binds to the admin's save bar, and multiple instances would create conflicting save states.