# Migrating to Spectrum 2

Learn how to migrate from React Spectrum v3 to Spectrum 2.

## AI-assisted migration (recommended)

If you're using an AI coding tool that supports [Agent Skills](https://agentskills.io/home), React Spectrum now includes a dedicated skill for guiding v3 to S2 upgrades.

To install the migration skill and the general S2 skill, run:

```bash
npx skills add https://react-spectrum.adobe.com --skill migrate-react-spectrum-v3-to-s2 --skill react-spectrum-s2
```

Then ask your agent to use the `migrate-react-spectrum-v3-to-s2` skill to migrate your project.

## Command-line tool

An automated upgrade assistant is available by running the following command in the project you want to upgrade:

```bash
npm install @react-spectrum/codemods s1-to-s2
```

To only upgrade specific components, provide a `--components` argument with a comma-separated list of components to upgrade:

```bash
npm install @react-spectrum/codemods s1-to-s2 --components=Button,TextField
```

The following arguments are also available:

- `--path` - Path to apply the upgrade changes to. Defaults to the current directory (`.`)
- `--dry` - Runs the upgrade assistant without making changes to components
- `--ignore-pattern` - Ignore files that match the provided glob expression. Defaults to `'**/node_modules/**'`
- `--agent` - Runs the upgrade assistant non-interactively for AI tools. This skips prompts, package installation, and macro setup, so `@react-spectrum/s2` must already be installed and resolvable

For cases that the upgrade assistant doesn't handle automatically or where you'd rather upgrade some components manually, use the guide below.

Note that <PendingBadge/> indicates that future changes are expected, and the current solution should be considered temporary.

## Components

### All components

- Update imports to use the `@react-spectrum/s2` package instead of `@adobe/react-spectrum` or individual packages like `@react-spectrum/button`
- Update [style props](v3/styling.md#style-props) to use the style macro instead. See the 'Style props' section below

### Accordion

- Update `Item` to be `Disclosure`. `Disclosure` should now consist of two children: `DisclosureTitle` and `DisclosurePanel`. Note that you can now add interactive elements inside the header and adjacent to the title by using the `DisclosureHeader` component with the `DisclosureTitle` and interactive elements inside.
- Update `Item`'s title prop to be a child of `DisclosureTitle`
- Update children of `Item` to be children of `DisclosurePanel`
- Update `key` to be `id` (and keep `key` if rendered inside `array.map`)
- Remove `disabledKeys` and add `isDisabled` to individual `Disclosure` components
- Add `allowsMultipleExpanded` to allow multiple `Disclosure` components to be expanded at once (previously default behavior)

### ActionBar

- Remove `ActionBarContainer` and move `ActionBar` to `renderActionBar` prop of `TableView` or `CardView`
- Update `Item` to `ActionButton`
- Update root level `onAction` to be called via `onPress` on each `ActionButton`
- Apply `isDisabled` directly on each `ActionButton` or `ToggleButton` instead of root level `disabledKeys`
- Update `key` to be `id` (and keep `key` if rendered inside `array.map`)
- Convert dynamic collections render function to `items.map`
- <PendingBadge/> Comment out `buttonLabelBehavior` (it has not been implemented yet)

### ActionButton

No updates needed.

### ActionMenu

- <PendingBadge/> Comment out `closeOnSelect` (it has not been implemented yet)
- <PendingBadge/> Comment out `trigger` (it has not been implemented yet)
- Update `Item` to be a `MenuItem`

### ActionGroup

- Use `ActionButtonGroup` if you are migrating from an `ActionGroup` that didn't allow for selection. `ActionButtonGroup` takes `ActionButtons` as children.
- Use `ToggleButtonGroup` if you are migrating from an `ActionGroup` that used single or multiple selection. `ToggleButtonGroup` takes `ToggleButtons` as children.
- <PendingBadge/> Comment out `overflowMode` (it has not been implemented yet)
- <PendingBadge/> Comment out `buttonLabelBehavior` (it has not been implemented yet)
- <PendingBadge/> Comment out `summaryIcon` (it has not been implemented yet)
- Update root level `onAction` to called via `onPress` on each `ActionButton`
- Apply `isDisabled` directly on each `ActionButton` or `ToggleButton` instead of root level `disabledKeys`
- Update `key` to be `id` (and keep `key` if rendered inside `array.map`)
- Convert dynamic collections render function to `items.map`

### AlertDialog

No updates needed.

### Avatar

- <PendingBadge/> Comment out `isDisabled` (it has not been implemented yet)
- Update `size` to be a pixel value if it currently matches `'avatar-size-*'`

### Badge

- Change `variant="info"` to `variant="informative"`

### Breadcrumbs

- <PendingBadge/> Comment out `showRoot` (it has not been implemented yet)
- <PendingBadge/> Comment out `isMultiline` (it has not been implemented yet)
- <PendingBadge/> Comment out `autoFocusCurrent` (it has not been implemented yet)
- Remove `size="S"` (Small is no longer a supported size in Spectrum 2)
- Update `Item` to be a `Breadcrumb`

### Button

- Change `variant="cta"` to `variant="accent"`
- Change `variant="overBackground"` to `variant="primary" staticColor="white"`
- Change `style` to `fillStyle`
- Remove `isQuiet` (it is no longer supported in Spectrum 2)
- If `href` is present, the `Button` should be converted to a `LinkButton`
- Remove `elementType` (it is no longer supported in Spectrum 2)

### ButtonGroup

No updates needed.

### Calendar

No updates needed.

### Checkbox

No updates needed.

### CheckboxGroup

- Remove `showErrorIcon` (it has been removed due to accessibility issues)

### ColorArea

- Remove `size` and instead provide a size via the style macro (i.e. `styles={style({size: 20})}`)

### ColorField

- Remove `isQuiet` (it is no longer supported in Spectrum 2)
- Change `validationState="invalid"` to `isInvalid`
- Remove `validationState="valid"` (it is no longer supported in Spectrum 2)

### ColorSlider

- Remove `showValueLabel` (it has been removed due to accessibility issues)

### ColorSwatch

No updates needed.

### ColorWheel

- Remove `size` and instead provide a size via the style macro (i.e. `styles={style({size: 20})}`)

### ComboBox

- Change `menuWidth` value from a `DimensionValue` to a pixel value
- Remove `isQuiet` (it is no longer supported in Spectrum 2)
- Change `validationState="invalid"` to `isInvalid`
- Remove `validationState="valid"` (it is no longer supported in Spectrum 2)
- Update `Item` to be a `ComboBoxItem`

### ContextualHelpTrigger

- Component has been renamed to `UnavailableMenuItemTrigger`
- Replace `Dialog` with  `ContextualHelpPopover`, and child elements with their S2 counterparts.

### DateField

- Remove `isQuiet` (it is no longer supported in Spectrum 2)
- Change `validationState="invalid"` to `isInvalid`
- Remove `validationState="valid"` (it is no longer supported in Spectrum 2)

### DatePicker

- Remove `isQuiet` (it is no longer supported in Spectrum 2)
- Change `validationState="invalid"` to `isInvalid`
- Remove `validationState="valid"` (it is no longer supported in Spectrum 2)

### DateRangePicker

- Remove `isQuiet` (it is no longer supported in Spectrum 2)
- Change `validationState="invalid"` to `isInvalid`
- Remove `validationState="valid"` (it is no longer supported in Spectrum 2)

### Dialog

- Update children to move render props from being the second child of `DialogTrigger` to being a child of `Dialog`
- Remove `onDismiss` and use `onOpenChange` on the `DialogTrigger`, or `onDismiss` on the `DialogContainer` instead
- `Dialog` is now meant specifically for rendering modal dialogs only and follows the same preset layout as before
- If you are trying to create a dialog with a custom layout use `CustomDialog`
- If you are trying to create a fullscreen dialog use `FullscreenDialog`
- If you are trying to create a popover dialog use `Popover`
- Supports `isKeyboardDismissDisabled` in place of `DialogTrigger`
- Supports `isDismissible` in place of `DialogTrigger`. Note the fixed spelling from previous `isDismissible` prop.
- Supports `role: "dialog" | "alertdialog"`

### DialogContainer

- Remove `type`, this is dependent on the dialog level child that you use (e.g. `Dialog`, `FullscreenDialog`, `Popover`)
- Remove `isDismissable`, prop now exists on the dialog level component as `isDismissible`
- Remove `isKeyboardDismissDisabled`, prop now exists on the dialog level component

### DialogTrigger

- <PendingBadge/> Comment out `type="tray"` (`Tray` has not been implemented yet)
- <PendingBadge/> Comment out `mobileType` (`Tray` and other types have not been implemented yet for `Popover`)
- Remove `targetRef` (it is no longer supported in Spectrum 2)
- Update `children` to remove render props usage, and note that the `close` function was moved from `DialogTrigger` to `Dialog`
- Remove `containerPadding`, prop now exists on the `Popover` component
- Remove `crossOffset`, prop now exists on the `Popover` component
- Remove `hideArrow`, prop now exists on the `Popover` component
- Remove `isDismissable`, prop now exists on the dialog level component as `isDismissible`
- Remove `isKeyboardDismissDisabled`, prop now exists on the dialog level component
- Remove `offset`, prop now exists on the `Popover` component
- Remove `placement`, prop now exists on the `Popover` component
- Remove `shouldFlip`, prop now exists on the `Popover` component
- Remove `type`, this is dependent on the dialog level child that you use (e.g. `Dialog`, `FullscreenDialog`, `Popover`)

### Divider

- Remove Divider component if within a Dialog (Updated design for Dialog in Spectrum 2)

### Flex

- Update `Flex` to be a `div` and apply flex styles using the style macro (i.e. `<div className={style({display: 'flex'})} />`)

### Form

- Remove `isQuiet` (it is no longer supported in Spectrum 2)
- Remove `isReadOnly` (it is no longer supported in Spectrum 2)
- Remove `validationState` (it is no longer supported in Spectrum 2)
- Remove `validationBehavior` (it is no longer supported in Spectrum 2)

### Grid

- Update `Grid` to be a `div` and apply grid styles using the style macro (i.e. `<div className={style({display: 'grid'})} />`)

### IllustratedMessage

- Update illustrations to be from `@react-spectrum/s2/illustrations`. See Illustrations

### InlineAlert

- Change `variant="info"` to `variant="informative"`

### Item

- If within `Menu`: Update `Item` to be a `MenuItem`
- If within `ActionMenu`: Update `Item` to be a `MenuItem`
- If within `TagGroup`: Update `Item` to be a `Tag`
- If within `Breadcrumbs`: Update `Item` to be a `Breadcrumb`
- If within `Picker`: Update `Item` to be a `PickerItem`
- If within `ComboBox`: Update `Item` to be a `ComboBoxItem`
- If within `ListView`: Update `Item` to be a `ListViewItem`
- If within `TabList`: Update `Item` to be a `Tab`
- If within `TabPanels`: Update `Item` to be a `TabPanel` and remove surrounding `TabPanels`
- Update `key` to be `id` (and keep `key` if rendered inside `array.map`)

### Link

- Change `variant="overBackground"` to `staticColor="white"`
- If `a` was used inside `Link` (legacy API), remove the `a` and apply props (i.e `href`) directly to `Link`

### ListView

- <PendingBadge/> Comment out `density` (it has not been implemented yet)
- <PendingBadge/> Comment out `dragAndDropHooks` (it has not been implemented yet)

### Menu

- Update `Item` to be a `MenuItem`

### MenuTrigger

- Rename `closeOnSelect` to `shouldCloseOnSelect` and move to `Menu`

### NumberField

- Remove `isQuiet` (it is no longer supported in Spectrum 2)
- Change `validationState="invalid"` to `isInvalid`
- Remove `validationState="valid"` (it is no longer supported in Spectrum 2)

### Picker

- Change `menuWidth` value from a `DimensionValue` to a pixel value
- Remove `isQuiet` (it is no longer supported in Spectrum 2)
- Change `validationState="invalid"` to `isInvalid`
- Remove `validationState="valid"` (it is no longer supported in Spectrum 2)
- Update `Item` to be a `PickerItem`
- Change `isLoading` to `loadingState` and provide the appropriate loading state.
- Update `defaultSelectedKey` and `selectedKey` to be `defaultValue` and `value` respectively. See the [Picker](Picker.md#value) documentation for more details.

### ProgressBar

- Change `variant="overBackground"` to `staticColor="white"`
- <PendingBadge/> Comment out `labelPosition` (it has not been implemented yet)
- <PendingBadge/> Comment out `showValueLabel` (it has not been implemented yet)

### ProgressCircle

- Change `variant="overBackground"` to `staticColor="white"`

### Radio

No updates needed.

### RadioGroup

- Change `validationState="invalid"` to `isInvalid`
- Remove `validationState="valid"` (it is no longer supported in Spectrum 2)
- Remove `showErrorIcon` (it has been removed due to accessibility issues)

### RangeCalendar

No updates needed.

### RangeSlider

- Remove `showValueLabel` (it has been removed due to accessibility issues)
- <PendingBadge/> Comment out `getValueLabel` (it has not been implemented yet)
- <PendingBadge/> Comment out `orientation` (it has not been implemented yet)

### SearchField

- <PendingBadge/> Comment out icon (it has not been implemented yet)
- Remove `isQuiet` (it is no longer supported in Spectrum 2)
- Change `validationState="invalid"` to `isInvalid`
- Remove `validationState="valid"` (it is no longer supported in Spectrum 2)

### Section

- If within `Menu`: Update `Section` to be a `MenuSection`
- If within `Picker`: Update `Section` to be a `PickerSection`

### Slider

- Remove `isFilled` (Slider is always filled in Spectrum 2)
- Remove `trackGradient` (Not supported in S2 design)
- Remove `showValueLabel` (it has been removed due to accessibility issues)
- <PendingBadge/> Comment out `getValueLabel` (it has not been implemented yet)
- <PendingBadge/> Comment out `orientation` (it has not been implemented yet)

### StatusLight

- Remove `isDisabled` (it is no longer supported in Spectrum 2)
- Change `variant="info"` to `variant="informative"`

### SubmenuTrigger

No updates needed.

### Switch

No updates needed.

### TableView

- For `Column` and `Row`: Update `key` to be `id` (and keep `key` if rendered inside `array.map`)
- For dynamic tables, pass a `columns` prop into `Row`
- For `Row`: Update dynamic render function to pass in `column` instead of `columnKey`
- Move `loadingState` and `onLoadMore` from `TableBody` to `TableView`
- For expandable rows, use `treeColumn` to designate your expandable column. `defaultExpanded`, `expandedKeys`, and `onExpandedChange` can be used to set and update your expanded rows. See the [TableView](TableView.md#expandable-rows) documentation for more details.

### Tabs

- Inside `TabList`: Update `Item` to be `Tab`
- Update `items` on `Tabs` to be on `TabList`
- Inside `TabPanels`: Update `Item` to be a `TabPanel` and remove the surrounding `TabPanels`
- Remove `isEmphasized` (it is no longer supported in Spectrum 2)
- Remove `isQuiet` (it is no longer supported in Spectrum 2)

### TagGroup

- Rename `actionLabel` to `groupActionLabel`
- Rename `onAction` to `onGroupAction`
- Change `validationState="invalid"` to `isInvalid`
- Update `Item` to be `Tag`

### TextArea

- <PendingBadge/> Comment out `icon` (it has not been implemented yet)
- Remove `isQuiet` (it is no longer supported in Spectrum 2)
- Change `validationState="invalid"` to `isInvalid`
- Remove `validationState="valid"` (it is no longer supported in Spectrum 2)

### TextField

- <PendingBadge/> Comment out `icon` (it has not been implemented yet)
- Remove `isQuiet` (it is no longer supported in Spectrum 2)
- Change `validationState="invalid"` to `isInvalid`
- Remove `validationState="valid"` (it is no longer supported in Spectrum 2)

### TimeField

- Remove `isQuiet` (it is no longer supported in Spectrum 2)
- Change `validationState="invalid"` to `isInvalid`
- Remove `validationState="valid"` (it is no longer supported in Spectrum 2)

### ToggleButton

No updates needed.

### Tooltip

- Remove `variant` (it is no longer supported in Spectrum 2)
- Remove `placement` and add to the parent `TooltipTrigger` instead
- Remove `showIcon` (it is no longer supported in Spectrum 2)
- Remove `isOpen` and add to the parent `TooltipTrigger` instead

### TooltipTrigger

- Update placement prop to have one value (i.e. Update `placement="bottom left"` to be `placement="bottom"`)

### TreeView

If migrating from TreeView version 3.0.0-beta.3 or before, please do the following. Otherwise, no updates needed.

- Update content within `TreeViewItem` to be wrapped in `TreeViewContentItem`

### View

- Update `View` to be a `div` and apply styles using the style macro

### Well

Update `Well` to be a `div` and apply styles using the style macro:

```tsx
<div className={style({
  display: 'block',
  textAlign: 'start',
  padding: 16,
  minWidth: 160,
  marginTop: 4,
  borderWidth: 1,
  borderRadius: 'sm',
  borderStyle: 'solid',
  borderColor: 'transparent-black-75',
  font: 'body-sm'
})} />
```

## Style props

React Spectrum v3 supported a limited set of style props for layout and positioning using Spectrum-defined values. Usage of these should be updated to instead use the style macro.

### Border width

Affected style props: `borderWidth`, `borderStartWidth`, `borderEndWidth`, `borderTopWidth`, `borderBottomWidth`, `borderXWidth`, `borderYWidth`.

Border widths should be updated to use pixel values. Use the following mappings:

| Spectrum 1 | Spectrum 2 |
| ------ | ------ |
| `'none'` | `0` |
| `'thin'` | `1` |
| `'thick'` | `2` |
| `'thicker'` | `4` |
| `'thickest'` | `'[8px]'` |

### Border radius

Affected style props: `borderRadius`, `borderTopStartRadius`, `borderTopEndRadius`, `borderBottomStartRadius`, `borderBottomEndRadius`.

Border radius values should be updated to use pixel values. Use the following mappings:

| Spectrum 1 | Spectrum 2 |
| ------ | ------ |
| `'xsmall'` | `'[1px]'` |
| `'small'` | `'sm'` |
| `'regular'` | `'default'` |
| `'medium'` | `'lg'` |
| `'large'` | `'xl'` |

### Dimension values

Affected style props: `width`, `minWidth`, `maxWidth`, `height`, `minHeight`, `maxHeight`, `margin`, `marginStart`, `marginEnd`, `marginTop`, `marginBottom`, `marginX`, `marginY`, `top`, `bottom`, `left`, `right`, `start`, `end`, `flexBasis`, `gap`, `columnGap`, `rowGap`, `padding`, `paddingX`, `paddingY`, `paddingStart`, `paddingEnd`, `paddingTop`, `paddingBottom`.

Dimension values should be converted to pixel values. Use the following mappings:

| Spectrum 1 | Spectrum 2 |
| ------ | ------ |
| `'size-0'` | `0` |
| `'size-10'` | `1` |
| `'size-25'` | `2` |
| `'size-40'` | `3` |
| `'size-50'` | `4` |
| `'size-65'` | `5` |
| `'size-75'` | `6` |
| `'size-85'` | `7` |
| `'size-100'` | `8` |
| `'size-115'` | `9` |
| `'size-125'` | `10` |
| `'size-130'` | `11` |
| `'size-150'` | `12` |
| `'size-160'` | `13` |
| `'size-175'` | `14` |
| `'size-200'` | `16` |
| `'size-225'` | `18` |
| `'size-250'` | `20` |
| `'size-275'` | `22` |
| `'size-300'` | `24` |
| `'size-325'` | `26` |
| `'size-350'` | `28` |
| `'size-400'` | `32` |
| `'size-450'` | `36` |
| `'size-500'` | `40` |
| `'size-550'` | `44` |
| `'size-600'` | `48` |
| `'size-675'` | `54` |
| `'size-700'` | `56` |
| `'size-800'` | `64` |
| `'size-900'` | `72` |
| `'size-1000'` | `80` |
| `'size-1200'` | `96` |
| `'size-1250'` | `100` |
| `'size-1600'` | `128` |
| `'size-1700'` | `136` |
| `'size-2000'` | `160` |
| `'size-2400'` | `192` |
| `'size-3000'` | `240` |
| `'size-3400'` | `272` |
| `'size-3600'` | `288` |
| `'size-4600'` | `368` |
| `'size-5000'` | `400` |
| `'size-6000'` | `480` |
| `'static-size-0'` | `0` |
| `'static-size-10'` | `1` |
| `'static-size-25'` | `2` |
| `'static-size-40'` | `3` |
| `'static-size-50'` | `4` |
| `'static-size-65'` | `5` |
| `'static-size-100'` | `8` |
| `'static-size-115'` | `9` |
| `'static-size-125'` | `10` |
| `'static-size-130'` | `11` |
| `'static-size-150'` | `12` |
| `'static-size-160'` | `13` |
| `'static-size-175'` | `14` |
| `'static-size-200'` | `16` |
| `'static-size-225'` | `18` |
| `'static-size-250'` | `20` |
| `'static-size-300'` | `24` |
| `'static-size-400'` | `32` |
| `'static-size-450'` | `36` |
| `'static-size-500'` | `40` |
| `'static-size-550'` | `44` |
| `'static-size-600'` | `48` |
| `'static-size-700'` | `56` |
| `'static-size-800'` | `64` |
| `'static-size-900'` | `72` |
| `'static-size-1000'` | `80` |
| `'static-size-1200'` | `96` |
| `'static-size-1700'` | `136` |
| `'static-size-2400'` | `192` |
| `'static-size-2600'` | `208` |
| `'static-size-3400'` | `272` |
| `'static-size-3600'` | `288` |
| `'static-size-4600'` | `368` |
| `'static-size-5000'` | `400` |
| `'static-size-6000'` | `480` |
| `'single-line-height'` | `32` |
| `'single-line-width'` | `192` |

### Break points

Break points previously used in style props can be used in the style macro with updated keys. Use the following mappings:

| Spectrum 1 | Spectrum 2 |
| ------ | ------ |
| `base` | `default` |
| `S` | `sm` |
| `M` | `md` |
| `L` | `lg` |
