SeloraXDEVELOPERS

Merchant Settings

Merchant Settings

Extensions can declare a settings schema that defines configurable fields. Merchants fill in these fields from the dashboard's extension configuration panel. Your extension reads the values at runtime and adjusts its behavior accordingly.

This lets merchants customize your extension — choosing a display color, toggling features, entering API keys, selecting options — without you needing to build a separate settings page.

How It Works

  1. You define a settings_schema array in your extension config.
  2. The platform renders a settings form for merchants in the dashboard (Settings > Apps > [App] > Extensions).
  3. The merchant fills in the fields and saves.
  4. Your extension reads the values from {{settings.key}} (JSON mode) or selorax.settings (sandbox mode).

Settings Field Types

TypeDescriptionRendered As
textSingle-line text inputText field
numberNumeric inputNumber field
toggleBoolean on/off switchToggle switch
selectDropdown with predefined optionsSelect dropdown
textareaMulti-line text inputText area
colorColor valueColor picker

Settings Schema Format

Each field in the settings_schema array is an object with these properties:

FieldTypeRequiredDescription
keystringYesUnique identifier for this setting. Used to read the value at runtime.
labelstringYesHuman-readable label shown to the merchant.
typestringYesOne of: text, number, toggle, select, textarea, color
defaultanyNoDefault value when the merchant has not configured a value.
descriptionstringNoHelp text shown below the field.
placeholderstringNoPlaceholder text for text/textarea/number fields.
requiredbooleanNoWhether the merchant must fill in this field. Default: false
optionsarrayselect onlyArray of { label, value } objects for the dropdown.

Example Schema

{
  "extension_id": "discount-banner",
  "target": "checkout.block",
  "title": "Discount Banner",
  "mode": "json",
  "settings_schema": [
    {
      "key": "enabled",
      "label": "Enable Banner",
      "type": "toggle",
      "default": true,
      "description": "Show or hide the discount banner in checkout."
    },
    {
      "key": "banner_text",
      "label": "Banner Text",
      "type": "text",
      "default": "Use code SAVE10 for 10% off!",
      "placeholder": "Enter banner message...",
      "required": true
    },
    {
      "key": "discount_percent",
      "label": "Discount Percentage",
      "type": "number",
      "default": 10,
      "description": "The discount percentage to apply."
    },
    {
      "key": "banner_color",
      "label": "Banner Color",
      "type": "color",
      "default": "#2563eb",
      "description": "Background color of the banner."
    },
    {
      "key": "banner_position",
      "label": "Banner Position",
      "type": "select",
      "default": "top",
      "options": [
        { "label": "Top of page", "value": "top" },
        { "label": "Bottom of page", "value": "bottom" },
        { "label": "Inline with items", "value": "inline" }
      ]
    },
    {
      "key": "custom_css",
      "label": "Custom CSS",
      "type": "textarea",
      "default": "",
      "placeholder": "Optional custom styles...",
      "description": "Advanced: enter custom CSS to style the banner."
    }
  ],
  "ui": { ... }
}

Reading Settings in JSON Mode

In JSON extensions, use template expressions to access merchant settings:

{
  "type": "Banner",
  "props": {
    "title": "{{settings.banner_text}}",
    "status": "info",
    "when": "{{settings.enabled}}"
  }
}

The {{settings.key}} syntax resolves to the merchant's configured value, or the default value from the schema if the merchant has not configured it.

Full JSON Example

Here is the complete discount banner extension using merchant settings:

{
  "extension_id": "discount-banner",
  "target": "checkout.block",
  "title": "Discount Banner",
  "mode": "json",
  "settings_schema": [
    {
      "key": "enabled",
      "label": "Enable Banner",
      "type": "toggle",
      "default": true
    },
    {
      "key": "banner_text",
      "label": "Banner Text",
      "type": "text",
      "default": "Use code SAVE10 for 10% off!",
      "required": true
    },
    {
      "key": "discount_percent",
      "label": "Discount Percentage",
      "type": "number",
      "default": 10
    },
    {
      "key": "banner_color",
      "label": "Banner Color",
      "type": "color",
      "default": "#2563eb"
    },
    {
      "key": "banner_position",
      "label": "Banner Position",
      "type": "select",
      "default": "top",
      "options": [
        { "label": "Top of page", "value": "top" },
        { "label": "Bottom of page", "value": "bottom" }
      ]
    }
  ],
  "ui": {
    "type": "Card",
    "props": {
      "padding": "none",
      "when": "{{settings.enabled}}"
    },
    "children": [
      {
        "type": "Banner",
        "props": {
          "title": "{{settings.banner_text}}",
          "status": "info"
        }
      },
      {
        "type": "Text",
        "props": {
          "content": "Discount: {{settings.discount_percent}}% off your order",
          "align": "center",
          "variant": "body",
          "weight": "semibold"
        }
      }
    ]
  }
}

When a merchant sets enabled to false, the entire card is hidden. When they change banner_text, the banner message updates. No code change or redeployment is needed.

Reading Settings in Sandbox Mode

In sandbox extensions, merchant settings are available on the selorax.settings object. This is populated automatically when the host sends the selorax:init message.

const { selorax, Card, Banner, Text, BlockStack } = require('@selorax/ui');
 
selorax.ready();
 
const settings = selorax.settings;
 
if (settings.enabled) {
  selorax.render(
    Card({ padding: 'none' },
      BlockStack({ gap: 'md' },
        Banner({
          title: settings.banner_text || 'Special offer!',
          status: 'info'
        }),
        Text({
          content: `Discount: ${settings.discount_percent || 10}% off your order`,
          align: 'center',
          weight: 'semibold'
        })
      )
    )
  );
} else {
  // Extension is disabled by merchant — render nothing or a minimal placeholder
  selorax.render(
    Text({ content: '' })
  );
}

Reacting to Settings Changes

If the merchant updates settings while your extension is loaded, the host sends a selorax:context_update message. Register a listener to re-render:

selorax.onContextUpdate((context) => {
  // Settings may have changed — re-render
  render();
});

Dashboard UI for Merchants

When a merchant navigates to Settings > Apps and selects an installed app, they see a list of extensions with their settings. The dashboard renders each setting field based on the settings_schema:

  • toggle fields appear as on/off switches.
  • text fields appear as text inputs with optional placeholder.
  • number fields appear as numeric inputs.
  • select fields appear as dropdown menus with the defined options.
  • textarea fields appear as multi-line text areas.
  • color fields appear as color pickers.

Each field shows its label and description. Required fields are marked. The merchant clicks "Save" to persist their settings, which are stored in the installation metadata under extension_config[extension_id].merchant_settings.

Merchants can also:

  • Enable/disable each extension with a toggle.
  • Reorder extensions that share the same target (e.g., multiple blocks on the order detail page).

Example: Configurable Shipping Estimator

This example shows a product detail block that estimates shipping cost based on merchant-configured rates.

Extension Config

{
  "extension_id": "shipping-estimator",
  "target": "product.detail.block",
  "title": "Shipping Estimator",
  "mode": "json",
  "settings_schema": [
    {
      "key": "enabled",
      "label": "Show Estimator",
      "type": "toggle",
      "default": true
    },
    {
      "key": "flat_rate",
      "label": "Flat Shipping Rate (BDT)",
      "type": "number",
      "default": 60,
      "description": "Standard shipping cost."
    },
    {
      "key": "free_threshold",
      "label": "Free Shipping Threshold (BDT)",
      "type": "number",
      "default": 2000,
      "description": "Orders above this amount get free shipping."
    },
    {
      "key": "free_shipping_text",
      "label": "Free Shipping Message",
      "type": "text",
      "default": "Free shipping on orders over {{threshold}}!",
      "description": "Message shown when free shipping applies."
    },
    {
      "key": "estimation_method",
      "label": "Estimation Method",
      "type": "select",
      "default": "flat",
      "options": [
        { "label": "Flat rate", "value": "flat" },
        { "label": "Weight-based", "value": "weight" },
        { "label": "Zone-based", "value": "zone" }
      ]
    }
  ],
  "ui": {
    "type": "Card",
    "props": {
      "title": "Shipping",
      "when": "{{settings.enabled}}"
    },
    "children": [
      {
        "type": "BlockStack",
        "props": { "gap": "sm" },
        "children": [
          {
            "type": "KeyValue",
            "props": {
              "label": "Shipping Cost",
              "value": "{{settings.flat_rate}} BDT"
            }
          },
          {
            "type": "KeyValue",
            "props": {
              "label": "Free Shipping Over",
              "value": "{{settings.free_threshold}} BDT"
            }
          },
          {
            "type": "Badge",
            "props": {
              "content": "{{settings.estimation_method}}",
              "variant": "info"
            }
          }
        ]
      }
    ]
  }
}

What the Merchant Sees

  1. In Settings > Apps > Shipping Estimator, the merchant sees a form with five fields:

    • A toggle for "Show Estimator" (default: on)
    • A number input for "Flat Shipping Rate" (default: 60)
    • A number input for "Free Shipping Threshold" (default: 2000)
    • A text input for "Free Shipping Message"
    • A dropdown for "Estimation Method" with three options
  2. The merchant changes the flat rate to 80 and the threshold to 1500, then saves.

  3. On the product detail page, the "Shipping" card now shows "80 BDT" as the shipping cost and "1500 BDT" as the free shipping threshold.

No redeployment, no code change, no developer involvement.

Tips

  • Always provide defaults. If a merchant installs your app and never touches settings, the extension should work with sensible defaults.

  • Keep the schema small. Five to ten settings is a good maximum. If you need more complex configuration, use a settings page (settings.page target) instead.

  • Use description generously. Merchants are not developers. Explain what each setting does in plain language.

  • Validate on the backend. Settings are user input. If your call_backend action uses a setting value, validate it server-side.

  • Use toggle for feature flags. If a merchant might want to turn off part of your extension, expose it as a toggle rather than requiring them to uninstall.

What's Next