---
title: Migrate Labelled from Polaris React
description: >-
  Replace Polaris React Labelled with field-owned label, details, required,
  disabled, read-only, and error properties.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/labelled
  md: >-
    https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/labelled.md
api_name: app-home
---

# Migrate Labelled from Polaris React

Polaris React `Labelled` combines a label, help text, validation, required state, and an optional action around a custom control. Prefer a Polaris web-component field that owns those relationships directly.

***

## Migrate labelled field content

## Migrating labelled field guidance and errors

##### Polaris web components

```tsx
import {useState} from 'react';

export function BrandColor() {
  const [color, setColor] = useState('#008060');

  return (
    <s-grid gridTemplateColumns="1fr auto" gap="small" alignItems="start">
      <s-color-field
        label="Brand color"
        name="brandColor"
        value={color}
        details="Used for buttons and links"
        required
        onChange={(event) => setColor(event.currentTarget.value)}
      ></s-color-field>
      <s-button variant="tertiary" onClick={() => setColor('#008060')}>
        Reset
      </s-button>
    </s-grid>
  );
}
```

##### Polaris React

```tsx
import {useState} from 'react';
import {Labelled, TextField} from '@shopify/polaris';

export function BrandColor() {
  const [color, setColor] = useState('#008060');

  return (
    <Labelled
      id="brand-color"
      label="Brand color"
      helpText="Used for buttons and links"
      requiredIndicator
      action={{content: 'Reset', onAction: () => setColor('#008060')}}
    >
      <TextField
        label="Brand color value"
        labelHidden
        value={color}
        onChange={setColor}
        autoComplete="off"
      />
    </Labelled>
  );
}
```

***

## Replace Labelled properties

| Polaris React | Polaris web components | Migration notes |
| - | - | - |
| `label` | `label` on the field or choice list | Rewrite React-node labels as concise text. |
| `helpText` | `details` on the field or `s-text slot="details"` on a choice | Keep help with the value or option it describes. |
| `error` | `error` on the field or field group | Replace boolean-only errors with an actionable message. |
| `requiredIndicator` | `required` on the field | Keep indication and validation behavior together. |
| `labelHidden` | `labelAccessibilityVisibility="exclusive"` where supported | Keep the accessible label. |
| `disabled` and `readOnly` | `disabled` and `readOnly` on the field | Preserve which state the business rule requires. |
| `action` | A separate `s-button` beside the field | Keep the action outside the label and give it a self-contained name. |
| `id` | Remove unless app logic needs it | The field component owns its internal accessible relationships. |
| `children` | The destination field or complete custom composite | Don't wrap a labelled field with a second label. |

For a label action such as **Reset**, use `s-grid` with the field and an adjacent button. The button should say what it resets, such as **Reset brand color**, in visible text or `accessibilityLabel`.

If no destination field fits, rebuild the custom composite with native `fieldset` and `legend` when it represents a group. Connect help and errors programmatically and verify the accessibility tree before removing `Labelled`.

***

## Test the migration

* Verify label, details, and error are exposed with the intended control or group.
* Exercise required, optional, disabled, read-only, valid, and invalid states.
* Run the adjacent action and confirm it updates both the displayed and submitted value.
* Test long translated labels, details, and errors at narrow widths.
* Check focus order so label actions don't interrupt the control unexpectedly.

***

## Remove Polaris React

After each destination owns its field relationships, remove `Labelled`, `errorID`, `helpTextID`, and compatibility wrappers. Remove `@shopify/polaris` only after no other route in scope imports it.

***

## Related guidance

* [Text field component](https://shopify.dev/docs/api/app-home/web-components/forms/text-field)
* [Migrate InlineError from Polaris React](https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/inline-error)
* [Color field component](https://shopify.dev/docs/api/app-home/web-components/forms/color-field)

***
