---
title: Migrate Stepper to the Polaris number field component
description: >-
  Learn how to migrate the Stepper component to Polaris web components in
  checkout and customer account UI extensions.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/checkout/migrate-to-web-components/stepper
  md: >-
    https://shopify.dev/docs/apps/build/checkout/migrate-to-web-components/stepper.md
---

# Migrate Stepper to the Polaris number field component

The Polaris number field component renders a numeric input. It replaces the previous [`Stepper`](https://shopify.dev/docs/api/checkout-ui-extensions/2025-07/ui-components/forms/stepper) component and is available as [`<s-number-field>`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field) in API versions 2025-10 and newer. The previous `Stepper` component always showed increment and decrement buttons. On the Polaris number field, [`controls`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#properties-propertydetail-controls) defaults to `'auto'`, which lets the surface decide whether to show the buttons. To guarantee the previous behavior, set `controls="stepper"` explicitly.

## Showing stepper buttons

##### Latest (Preact)

```jsx
import '@shopify/ui-extensions/preact';
import {render} from 'preact';

export default function extension() {
  render(<Extension />, document.body);
}

function Extension() {
  return (
    <s-number-field
      label="Quantity"
      controls="stepper"
      defaultValue="1"
      min={1}
      max={10}
    />
  );
}
```

##### Pre-Polaris (2025-07)

```jsx
import {
  reactExtension,
  Stepper,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
  'purchase.checkout.block.render',
  () => <Extension />,
);

function Extension() {
  return (
    <Stepper label="Quantity" value={1} min={1} max={10} />
  );
}
```

***

## Updated properties

The following properties are different in the Polaris number field component.

### on​Change

The previous `Stepper` `onChange` prop was called with the new numeric value, and an empty field was represented as `undefined`. On the Polaris number field, the handler receives an `Event` instead. Read the value from `event.currentTarget.value`, which is now a `string`. Don't cast it with `Number(...)` directly — `Number('')` evaluates to `0`, so a cleared field would be reinterpreted as zero. Check for an empty string first, then cast:

## Migrating onChange

##### Latest (Preact)

```jsx
import '@shopify/ui-extensions/preact';
import {render} from 'preact';

export default function extension() {
  render(<Extension />, document.body);
}

function Extension() {
  return (
    <s-number-field
      label="Quantity"
      controls="stepper"
      onChange={(event) => {
        const raw = event.currentTarget.value;
        const value = raw === '' ? undefined : Number(raw);
        console.log('Value:', value);
      }}
    />
  );
}
```

##### Pre-Polaris (2025-07)

```jsx
import {
  reactExtension,
  Stepper,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
  'purchase.checkout.block.render',
  () => <Extension />,
);

function Extension() {
  return (
    <Stepper
      label="Quantity"
      onChange={(value) => console.log('Value:', value)}
    />
  );
}
```

### on​Input

The previous `Stepper` `onInput` prop was called with the new numeric value, and an empty field was represented as `undefined`. On the Polaris number field, the handler receives an `Event`. Read the value from `event.currentTarget.value`, which is now a `string`. Check for an empty string before casting with `Number(...)` — `Number('')` is `0`, which would reinterpret a cleared field as zero.

### on​Blur and on​Focus

The previous `Stepper` `onBlur` and `onFocus` props were called with no arguments. On the Polaris number field, both handlers now receive an `Event`.

### value

The previous `Stepper` `value` prop was a `number`. On the Polaris number field, [`value`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#properties-propertydetail-value) is a `string`. Use [`defaultValue`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#properties-propertydetail-defaultvalue) (uncontrolled) or `value` (controlled) to set the initial value.

## Migrating value

##### Latest (Preact)

```jsx
import '@shopify/ui-extensions/preact';
import {render} from 'preact';

export default function extension() {
  render(<Extension />, document.body);
}

function Extension() {
  return (
    <s-number-field
      label="Quantity"
      controls="stepper"
      defaultValue="1"
      min={1}
      max={10}
    />
  );
}
```

##### Pre-Polaris (2025-07)

```jsx
import {
  reactExtension,
  Stepper,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
  'purchase.checkout.block.render',
  () => <Extension />,
);

function Extension() {
  return (
    <Stepper label="Quantity" value={1} min={1} max={10} />
  );
}
```

### readonly

The previous `Stepper` `readonly` prop is now [`readOnly`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#properties-propertydetail-readonly) (capital `O`).

### min and max defaults

The previous `Stepper` `min` defaulted to `0` and `max` had no default. On the Polaris number field, [`min`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#properties-propertydetail-min) defaults to `-Infinity` and [`max`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#properties-propertydetail-max) defaults to `Infinity`. If your code relied on the previous `min={0}` default, set `min={0}` explicitly.

### icon

If you use the [`icon`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#properties-propertydetail-icon) property, then update icon names to their Polaris web component equivalents. The number field uses the same icon names as the Polaris [icon](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/media-and-visuals/icon) component.

**Note:**

This table lists only icon values that need more than a camelCase-to-kebab-case rename. If an icon isn't listed here, then convert its previous camelCase name to kebab-case. For example, `arrowLeft` becomes `arrow-left`.

| Previous icon | New icon |
| - | - |
| `'checkmark'` | `'check'` |
| `'close'` | `'x'` |
| `'critical'` | `'alert-circle'` |
| `'error'` | `'x-circle'` |
| `'errorFill'` | `'x-circle-filled'` |
| `'gift'` | `'gift-card'` |
| `'giftFill'` | `'gift-card'` |
| `'hamburger'` | `'menu'` |
| `'hollowCircle'` | `'circle'` |
| `'horizontalDots'` | `'menu-horizontal'` |
| `'infoFill'` | `'info-filled'` |
| `'list'` | `'list-bulleted'` |
| `'magnify'` | `'search'` |
| `'marker'` | `'location'` |
| `'orderBox'` | `'order'` |
| `'pen'` | `'edit'` |
| `'question'` | `'question-circle'` |
| `'questionFill'` | `'question-circle-filled'` |
| `'starFill'` | `'star-filled'` |
| `'success'` | `'check-circle'` |
| `'verticalDots'` | `'menu-vertical'` |
| `'warning'` | `'alert-triangle'` |
| `'warningFill'` | `'alert-triangle-filled'` |

***

## New properties

The Polaris number field component introduces the following new properties:

| New prop | Type | Description |
| - | - | - |
| [`controls`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#properties-propertydetail-controls) | `'auto'` \| `'stepper'` \| `'none'` | Sets the type of controls displayed in the field. `'stepper'` shows increment and decrement buttons, `'none'` hides them, and `'auto'` (the default) lets the surface decide. |
| [`defaultValue`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#properties-propertydetail-defaultvalue) | `string` | Sets the initial value for uncontrolled usage. |
| [`suffix`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#properties-propertydetail-suffix) | `string` | Text content to render after the value. |
| [`autocomplete`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#properties-propertydetail-autocomplete) | `string` | A hint to the browser about the autofill value for the field. |
| [`inputMode`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#properties-propertydetail-inputmode) | `'decimal'` \| `'numeric'` | Hints at the type of virtual keyboard to display. |
| [`labelAccessibilityVisibility`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#properties-propertydetail-labelaccessibilityvisibility) | `'visible'` \| `'exclusive'` | Controls whether the label is visible or only available to assistive technology. |

### accessory

The Polaris number field exposes an [`accessory`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#slots-propertydetail-accessory) slot for supplementary interactive content (a button or clickable with text content). The previous `Stepper` had no equivalent — the slot is a new capability on `<s-number-field>`. Use it for actions adjacent to the input, such as a "Use max" button:

## Adding an accessory to s-number-field

```tsx
import '@shopify/ui-extensions/preact';
import {render} from 'preact';


export default function extension() {
  render(<Extension />, document.body);
}


function Extension() {
  return (
    <s-number-field label="Quantity" defaultValue="1" min={0} max={10}>
      <s-button slot="accessory">Use max</s-button>
    </s-number-field>
  );
}
```

For static unit indicators like `kg` or `%`, use the [`prefix`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#properties-propertydetail-prefix) and [`suffix`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/number-field#properties-propertydetail-suffix) props instead:

```tsx
<s-number-field label="Weight" defaultValue="1" min={0} suffix="kg" />
```

***

## Removed properties

### accessibility​Description

The previous `Stepper` `accessibilityDescription` prop has been removed. Use `label` or the field's built-in error and validation messaging to communicate additional context to screen readers.

***
