---
title: Migrate ToggleButtonGroup to the Polaris choice list component
description: >-
  Learn how to migrate the ToggleButtonGroup and ToggleButton components 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/toggle-button-group
  md: >-
    https://shopify.dev/docs/apps/build/checkout/migrate-to-web-components/toggle-button-group.md
---

# Migrate ToggleButtonGroup to the Polaris choice list component

The previous [`ToggleButtonGroup`](https://shopify.dev/docs/api/checkout-ui-extensions/2025-07/ui-components/forms/togglebuttongroup) and [`ToggleButton`](https://shopify.dev/docs/api/checkout-ui-extensions/2025-07/ui-components/forms/togglebutton) components have been replaced by [`<s-choice-list>`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/choice-list) with `variant="grid"` and [`<s-choice>`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/choice-list#choice) children, available in API versions 2025-10 and newer.

The `grid` variant renders each choice as a selectable block without checkbox or radio controls, matching the visual appearance of the previous toggle buttons. See the [choice list migration guide](https://shopify.dev/docs/apps/build/checkout/migrate-to-web-components/choice-list) for additional property changes shared across all choice list variants.

***

## Component mapping

| Previous component | New component | Notes |
| - | - | - |
| `ToggleButtonGroup` | [`<s-choice-list variant="grid">`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/choice-list) | Wraps the set of choices. |
| `ToggleButton` | [`<s-choice>`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/choice-list#choice) | Each selectable option. Use the `value` attribute instead of `id`. |

***

## When to use Press​Button instead

`<s-choice-list variant="grid">` is the right fit for a mutually-exclusive group that's submitted by a single `name` — pick-one behaviour with form semantics. If the buttons aren't mutually exclusive, or you have a single standalone toggle, use [`<s-press-button>`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/actions/press-button) instead. Each `<s-press-button>` tracks its own state through [`pressed`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/actions/press-button#properties-propertydetail-pressed) (or [`defaultPressed`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/actions/press-button#properties-propertydetail-defaultpressed) for uncontrolled usage), so you can have several pressed at once.

## Migrating independent toggles to s-press-button

##### Latest (Preact)

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

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

function Extension() {
  const [filters, setFilters] = useState({gift: false, express: false});
  const toggle = (key) =>
    setFilters((prev) => ({...prev, [key]: !prev[key]}));

  return (
    <s-stack direction="inline" gap="small-200">
      <s-press-button
        pressed={filters.gift}
        onClick={() => toggle('gift')}
      >
        Gift wrap
      </s-press-button>
      <s-press-button
        pressed={filters.express}
        onClick={() => toggle('express')}
      >
        Express shipping
      </s-press-button>
    </s-stack>
  );
}
```

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

```tsx
import {
  reactExtension,
  ToggleButtonGroup,
  ToggleButton,
} from '@shopify/ui-extensions-react/checkout';
import {useState} from 'react';

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

function Extension() {
  const [filters, setFilters] = useState({gift: false, express: false});

  return (
    <ToggleButtonGroup value={undefined}>
      <ToggleButton
        id="gift"
        onPress={() =>
          setFilters((prev) => ({...prev, gift: !prev.gift}))
        }
      >
        Gift wrap
      </ToggleButton>
      <ToggleButton
        id="express"
        onPress={() =>
          setFilters((prev) => ({...prev, express: !prev.express}))
        }
      >
        Express shipping
      </ToggleButton>
    </ToggleButtonGroup>
  );
}
```

For the standalone single-button case, see the [ToggleButton migration guide](https://shopify.dev/docs/apps/build/checkout/migrate-to-web-components/toggle-button).

***

## Updated properties

### value and on​Change

The previous `ToggleButtonGroup` `value` prop (a single string) maps to `<s-choice-list>` [`values`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/choice-list#properties-propertydetail-values) (always a `string[]`). The `onChange` callback now receives an `Event` — read the current selection from `event.currentTarget.values`.

### Toggle​Button id

The previous `ToggleButton` `id` prop that identified the choice within the group is now the [`value`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/choice-list#choice-propertydetail-value) attribute on `<s-choice>`. The label text is passed as children.

## Migrating ToggleButtonGroup to s-choice-list variant=grid

##### Latest (Preact)

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

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

function Extension() {
  const [size, setSize] = useState('medium');

  return (
    <s-choice-list
      name="size"
      variant="grid"
      onChange={(event) => setSize(event.currentTarget.values[0])}
    >
      <s-choice value="small" selected={size === 'small'}>
        Small
      </s-choice>
      <s-choice value="medium" selected={size === 'medium'}>
        Medium
      </s-choice>
      <s-choice value="large" selected={size === 'large'}>
        Large
      </s-choice>
    </s-choice-list>
  );
}
```

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

```tsx
import {
  reactExtension,
  ToggleButtonGroup,
  ToggleButton,
} from '@shopify/ui-extensions-react/checkout';
import {useState} from 'react';

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

function Extension() {
  const [size, setSize] = useState('medium');

  return (
    <ToggleButtonGroup
      value={size}
      onChange={(value) => setSize(value)}
    >
      <ToggleButton id="small">Small</ToggleButton>
      <ToggleButton id="medium">Medium</ToggleButton>
      <ToggleButton id="large">Large</ToggleButton>
    </ToggleButtonGroup>
  );
}
```

***

## Removed properties

The following properties from the previous components are no longer available:

* `ToggleButton` `onPress` — no longer supported. Use the `onChange` event on the parent `<s-choice-list>` instead.
* `ToggleButton` `accessibilityLabel` — no longer supported. The label text is passed as children of `<s-choice>`.

***

## New properties

Using `<s-choice-list>` with `variant="grid"` gives access to all the choice list properties not available on the previous `ToggleButtonGroup`:

| New prop | Type | Description |
| - | - | - |
| [`label`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/choice-list#properties-propertydetail-label) | `string` | Sets the label text for the choice list. |
| [`error`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/choice-list#properties-propertydetail-error) | `string` | Sets an error message to display. |
| [`multiple`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/web-components/forms/choice-list#properties-propertydetail-multiple) | `boolean` | Enables multi-select. The previous `ToggleButtonGroup` only supported single selection. |

***
