# Canvas Kit 9.0 Upgrade Guide

This guide contains an overview of the changes in Canvas Kit v9. Please
[reach out](https://github.com/Workday/canvas-kit/issues/new?labels=bug&template=bug.md) if you have
any questions.

- [Codemod](#codemod)
- [New Components](#new-components)
  - [Table](#table)
- [Updated Terms](#updated-terms)
- [Removals](#removals)
  - [Drawer](#drawer)
  - [Layout and Column](#layout-and-column)
  - [composeModelHooks](#composemodelhook)
  - [Stack, HStack, and VStack](#stack-hstack-and-vstack)
  - [focusRing](#focusring)
  - [useCanvasTheme and getCanvasTheme](#usecanvastheme-and-getcanvastheme)
- [Deprecations](#deprecations)
  - [useThemeRTL](#usethemertl)
- [Token Updates](#token-updates)
  - [Depth](#depth)
- [Component Updates](#component-updates)
  - [Button](#button)
  - [Toast](#toast)
  - [Collection](#collection)
- [Utility Updates](#utility-updates)
  - [useTheme and getTheme](#usetheme-and-gettheme)
  - [useThemedRing](#usethemedring)
  - [composeHooks](#composehooks)
- [Glossary](#glossary)
  - [Main](#main)
  - [Preview](#preview)
  - [Labs](#labs)

## Codemod

We've provided a [codemod](https://github.com/Workday/canvas-kit/tree/master/modules/codemod) to
automatically update your code to work with most of the breaking changes in v9. **Breaking changes
handled by the codemod are marked with 🤖 in the Upgrade Guide.**

A codemod is a script that makes programmatic transformations on your codebase by traversing the
[AST](https://www.hypermod.io/docs/guides/understanding-asts), identifying patterns, and making
prescribed changes. This greatly decreases opportunities for error and reduces the number of manual
updates, which allows you to focus on changes that need your attention. **We highly recommend you
use the codemod for these reasons.**

If you're new to running codemods or if it's been a minute since you've used one, there are a few
things you'll want to keep in mind.

- Our codemods are meant to be run sequentially. For example, if you're using v7 of Canvas Kit,
  you'll need to run the v8 codemod before you run v9.
- The codemod will update your code to be compatible with the specified version, but it will **not**
  remove outdated dependencies or upgrade dependencies to the latest version. You'll need to upgrade
  dependencies on your own.
  - We recommend upgrading dependencies before running the codemod.
  - Always review your `package.json` files to make sure your dependency versions look correct.
- The codemod will not handle every breaking change in v9. You will likely need to make some manual
  changes to be compatible. Use our Upgrade Guide as a checklist.
- Codemods are not bulletproof.
  - Conduct a thorough PR and QA review of all changes to ensure no regressions were introduced.
  - As a safety precaution, we recommend committing the changes from the codemod as a single
    isolated commit (separate from other changes) so you can roll back more easily if necessary.

We're here to help! Automatic changes to your codebase can feel scary. You can always reach out to
our team. We'd be very happy to walk you through the process to set you up for success.

### Instructions

The easiest way to run our codemod is to use `npx`.

```sh
> npx @workday/canvas-kit-codemod v9 [path]
```

Be sure to provide specific directories that need to be updated via the `[path]` argument. This
decreases the amount of AST the codemod needs to traverse and reduces the chances of the script
having an error. For example, if your source code lives in `src/`, use `src/` as your `[path]`. Or,
if you have a monorepo with three packages using Canvas Kit, provide those specific packages as your
`[path]`.

Alternatively, if you're unable to run the codemod successfully using `npx`, you can install the
codemod package as a dev dependency, run it with `yarn`, and then remove the package after you're
finished.

```sh
> yarn add @workday/canvas-kit-codemod --dev
> yarn canvas-kit-codemod v9 [path]
> yarn remove @workday/canvas-kit-codemod
```

> The codemod only works on `.js`, `.jsx`, `.ts`, and `.tsx` files. You'll need to manually edit
> other file types (`.json`, `.mdx`, `.md`, etc.). You may need to run your linter after executing
> the codemod, as its resulting formatting (spacing, quotes, etc.) may not match your project
> conventions.

## New Components

### Table

We've introduced a new `Table`
[compound component](/get-started/for-developers/documentation/compound-components/) to the Preview
package. `Table` is a compound component that is used to present information in a two-dimensional
[table](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table) comprised of rows and
columns of cells containing data.

```tsx
import {Table} from '@workday/canvas-kit-preview-react/table';

export default function App() {
  return (
    <Table>
      <Table.Caption>Table Caption</Table.Caption>
      <Table.Head>
        <Table.Row>
          <Table.Header>Table Header</Table.Header>
          <Table.Header>Table Header</Table.Header>
        </Table.Row>
      </Table.Head>
      <Table.Body>
        <Table.Row>
          <Table.Header>Table Header</Table.Header>
          <Table.Header>Table Header</Table.Header>
        </Table.Row>
        <Table.Row>
          <Table.Header>Table Header</Table.Header>
          <Table.Cell>Table Data Cell</Table.Cell>
        </Table.Row>
        <Table.Row>
          <Table.Header>Table Header</Table.Header>
          <Table.Cell>Table Data Cell</Table.Cell>
        </Table.Row>
      </Table.Body>
      <Table.Footer>
        <Table.Row>
          <Table.Header>Table Header</Table.Header>
          <Table.Cell>Table Data Cell</Table.Cell>
        </Table.Row>
      </Table.Footer>
    </Table>
  );
}
```

## Updated Terms

We have updated two terms that were used in previous versions of Canvas Kit to better reflect their
meaning and intentions.

- **"Soft-Deprecation"** is now **"Deprecate/Deprecation"**

  - _Deprecate/Deprecation: We add the [@deprecated tag](https://jsdoc.app/tags-deprecated.html)
    from JSDoc to code that we plan to deprecate in the near future. Although you can still consume
    this code, we want consumers to move to a utility or component that is more stable._
    - _Previously, we also added "Deprecated" to a component name. For example, from `ComponentName`
      to `DeprecatedComponenntName`. As of 9.0, we longer do this._

- **"Hard-Deprecation"** is now **"Remove/Removal"**

  - _Remove/Removals: Removals are deletions from our codebase and you can no longer consume this
    component. We've either promoted or replaced a component or utility. You will need to follow the
    method prescribed in our upgrade guide to update your application. Please reach out to our team
    directly if you need additional help._

## Removals

Removals are deletions from our codebase and you can no longer consume this component. We've either
promoted or replaced a component or utility.

### Drawer

**PR:** [#1970](https://github.com/Workday/canvas-kit/pull/1970)

We've removed the `Drawer` component (for reference, see the
[`Drawer`](https://d2krrudi3mmzzw.cloudfront.net/v8/?path=/docs/labs-drawer--basic) from v8). Please
use the [`SidePanel`](/components/containers/side-panel/) in [Preview](#preview) instead.

> **Note:** The `SidePanel` in Main will eventually be replaced with the `SidePanel` in Preview. We
> recommend you use the `SidePanel` in Preview until then.

---

### Layout and Column

**PR:** [#2018](https://github.com/Workday/canvas-kit/pull/2018)

We've removed the `Layout` and `Column` components (for reference, see
[`Column and Layout`](https://d2krrudi3mmzzw.cloudfront.net/v8/?path=/docs/components-containers-column-and-layout--12-column-layout)
from v8). Please use [`Grid`](/components/layout/grid/) instead. While `Grid` is not a 1:1
replacement for `Layout` and `Column`, it can be used to generate the same types of layouts and
offers a more robust and flexible layout solution.

Please refer to our [Layout examples](/examples/layout/) for examples of how to implement common
layouts using `Grid`.

---

### composeModelHooks

**PR:** [#2180](https://github.com/Workday/canvas-kit/pull/2180)

We're removing this hook. It is a duplicate of `componseHooks` that was never used by anything. This
should have no impact on your code. We couldn't find any references to this function in any code
bases we have access to.

---

### Stack, HStack and VStack

**PR:** [#2012](https://github.com/Workday/canvas-kit/pull/2012)

We've removed the `Stack`, `HStack`, and `VStack` components (for reference, see
[`Stack`](https://d2krrudi3mmzzw.cloudfront.net/v8/?path=/docs/components-layout-stack--basic-stack)
from v8). Please use [`Flex`](/components/layout/flex/) instead. `Flex` supports the same consistent
spacing between its elements via the `gap` prop (analogous to the `spacing` prop from `Stack`).

```tsx
// v8
<Stack spacing="s">
  ...
</Stack>

// v9
<Flex gap="s">
  ...
</Flex>
```

The orientation of `VStack` elements can be replicated with `Flex` using `flexDirection`.

```tsx
// v8
<VStack>
  ...
</VStack>

// v9
<Flex flexDirection="column">
  ...
</Flex>
```

The `StackProps`, `HStackProps`, `VStackProps`, and `StackStyleProps` types have been removed as
well. All references to these types in your custom components will need to be replaced with
`FlexProps`.

🤖 The codemod will handle all of the changes above for you automatically.

> **Note:** If you were consuming `StackProps` previously for a custom component, be sure to change
> all references to the old `spacing` prop from `StackProps` to the `gap` prop from `FlexProps`.

---

### focusRing

**PR:** [#2034](https://github.com/Workday/canvas-kit/pull/2034)

We've removed memoization from `focusRing`. The `memoize` argument passed to `focusRing` is no
longer valid, and we've removed `memoizedFocusRing`. We were unable to find any examples of
`memoize` or `memoizedFocusRing` in use by our consumers.

---

### useCanvasTheme and getCanvasTheme

**PR:** [#2120](https://github.com/Workday/canvas-kit/pull/2120)

We've removed `useCanvasTheme` and `getCanvasTheme`. Please use `useTheme` and `getTheme` instead.

## Deprecations

We add the [@deprecated](https://jsdoc.app/tags-deprecated.html) from JSDoc to code that we plan to
deprecate in the near future. Al though you can still consume this code, we want consumers to move
to a utility or component that is more stable.

### useThemeRTL

**PR:** [#2119](https://github.com/Workday/canvas-kit/pull/2119)

We've deprecated `useThemeRTL` from [Labs](#labs). Although you may still use this utility, we
recommend using
[CSS logical properties](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties)
instead.

---

### composeHooks

The `composeHooks` types are now accurate. Before the types were incorrectly merged to equal `{}`.
This also affects components created using `createContainer` or `createSubcomponent`. The
`elemProps` type interface will now reflect all the incoming props from the hook properly. If you
get an error when passing `elemProps` from a hook using `composeHooks`, you may get a Typescript
error. Sometimes returning a generic object widens types and style or JSX attributes are more
strict. This can cause problems with JSX attributes like `position` which expects values like
`'relative' | 'absolute'` and doesn't accept a string.

For example:

```ts
return {
  position: 'relative',
}; // { 'position': string }
```

TypeScript doesn't know that this object interface cannot be mutated, so it will widen the
`position` type to a `string` which is now allowed when you pass the prop list to a JSX element.
You'll have to add an `as const` to either the property or the whole object to force Typescript to
narrow the type.

```ts
return {
  position: 'relative' as const, // forces the type to be `'relative'` instead of `string`
} as const; // OR add `as const` here to narrow the whole object.
```

`as const` instructs Typescript the type is `readonly`. Typescript knows readonly values or objects
cannot be changed and will therefore narrow the type for you.

---

## Token Updates

### Depth

**PR:** [#2091](https://github.com/Workday/canvas-kit/pull/2091)

In v7, we released an update to our depth tokens that was too bold and harsh for web applications.
We've modified the depth token styles to be more subtle and improve visual design. This change
affects all components which use depth tokens including `Card`, `Toast`, `Dialog`, `Popup`, `Modal`,
and `Menu`. We have not changed which depth values each component references (i.e., `Card` remains
at `depth[1]`).

## Component Updates

### Button

**PR:** [#1978](https://github.com/Workday/canvas-kit/pull/1978)

We've changed the default `type` attribute for all buttons to `type="button"`. Previously, the
`type` attribute was not being set which resulted in the buttons
[defaulting to `type="submit"`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attributes).

This affects all buttons which extend `BaseButton`:

- `PrimaryButton`
- `SecondaryButton`
- `TertiaryButton`
- `DeleteButton`
- `ToolbarDropdownButton` and `ToolbarIconButton`
- `Pill` and `Pill.IconButton`
- `SegmentedControl.Button` (Main)
- `SegmentedControl.Item` (Preview)
- `Pagination.PageButton`

Any buttons which extend any of the above are affected as well.

This resolves an [issue](https://github.com/Workday/canvas-kit/issues/1938) where clicking certain
buttons within a `form` element would unexpectedly submit the form. Additionally, the default action
of many form controls such as `input` and `textarea` is to click the first submit button; this led
to issues if the first submit button in the form was not intended to be a submit button (a common
mistake when buttons default to `type="submit"`).

This is a breaking change if you expected a button to submit by default, though we do not anticipate
this to be the case for most developers. If you _do_ intend for a button to act as a submit button
within a form, add `type="submit"` to the button.

---

### Toast

**PR:** [#2044](https://github.com/Workday/canvas-kit/pull/2044)

We've promoted `Toast` from [Labs](#labs) to [Main](#main). It replaces the `Toast` that was
previously in [Main](#main) (for reference, see
[`Toast`](https://d2krrudi3mmzzw.cloudfront.net/v8/?path=/docs/components-popups-toast--error) in
[Main](#main) from v8).

`Toast` is a [compound component](/get-started/for-developers/documentation/compound-components/)
which provides a flexible API and access to its internals via its subcomponents. It supports a new
`mode` prop which applies the proper accessibility features to the component based on the desired
mode: `status`, `alert`, or `dialog`.

```tsx
// v8
<Toast actionText="View more details" onActionClick={handleActionClick} onClose={handleClose}>
  Your workbook was successfully processed.
</Toast>

// v9
<Toast mode="dialog">
  <Toast.Icon icon={checkIcon} color={colors.greenApple400} />
  <Toast.Body>
    <Toast.Message>Your workbook was successfully processed.</Toast.Message>
    <Toast.Link onClick={handleActionClick}>View more details</Toast.Link>
  </Toast.Body>
	<Toast.CloseIcon aria-label="Close" onClick={handleClose} />
</Toast>
```

🤖 The codemod will rewrite your usages of the previous `Toast` in [Main](#main) to use the compound
component API of the new `Toast` in [Main](#main). `mode` will be set to `dialog` if the `Toast`
previously used `actionText` or `onActionClick`. The codemod will also update imports from the
[Labs](#labs) `Toast` to instead import from [Main](#main).

> **Note:** You will manually need to set `mode` to `alert` if your `Toast` conveys urgent and
> important information such as an error.

---

### Collection

Navigation was updated to use numerical indexes instead of string identifiers. The
`model.state.cursorId` is left unchanged. The change is to support virtual lists where navigation
knows where it needs to go, but the identifier may not be loaded yet. The mechanism for navigating
is private and should not breaking anything. If you created a custom navigation manager, the
signature has been changed.

The `useListModel` modelHook no longers sets the initial `cursorId` to the first item if no
`initialCursorId` config option is set. This functionality has been moved to the
`useListItemRovingFocus` elemProps hook. If you use `useListItemRovingFocus`, the behavior is
unchanged. If you need the first item to be set as the `cursorId` and you do not use
`useListItemRovingFocus`, you will have to add this functionality back to your collection logic.

The logic to set the `cursorId` to the first item should go into an item elemProps hook that
contains the following:

```ts
React.useEffect(() => {
  if (!model.state.cursorId && model.state.items.length) {
    model.events.goTo({id: model.state.items[0].id});
  }
}, [model.state.cursorId, model.state.items, model.events]);
```

## Utility Updates

### useTheme and getTheme

**PR:** [#2120](https://github.com/Workday/canvas-kit/pull/2120)

We've added error handling to `useTheme` if it's been used outside a functional component. We've
also added `getTheme` to provide access to a theme from `styled` or class components instead of
`useTheme`.

### useThemedRing

**PR:** [#2119](https://github.com/Workday/canvas-kit/pull/2119)

We've promoted `useThemedRing` from [Labs](#labs) to [Main](#main). `useThemedRing` allows you to
theme focus rings.

🤖 The codemod will update the import for this utility.

## Glossary

### Main

Our Main package of Canvas Kit tokens, components, and utilities at `@workday/canvas-kit-react` has
undergone a full design and a11y review and is approved for use in product.

Breaking changes to code in Main will only occur during major version updates and will always be
communicated in advance and accompanied by migration strategies.

---

### Preview

Our Preview package of Canvas Kit tokens, components, and utilities at
`@workday/canvas-kit-preview-react` has undergone a full design and a11y review and is approved for
use in product, but may not be up to the high code standards upheld in the [Main](#main) package.
Preview is analagous to code in beta.

Breaking changes are unlikely, but possible, and can be deployed to Preview at any time without
triggering a major version update, though such changes will be communicated in advance and
accompanied by migration strategies.

Generally speaking, our goal is to eventually promote code from Preview to [Main](#main).
Occasionally, a component with the same name will exist in both [Main](#main) and Preview (for
example, see Segmented Control in [Preview](/components/buttons/segmented-control/) and
[Main](https://d2krrudi3mmzzw.cloudfront.net/v8/?path=/docs/components-buttons-segmented-control--basic)).
In these cases, Preview serves as a staging ground for an improved version of the component with a
different API. The component in [Main](#main) will eventually be replaced with the one in Preview.

---

### Labs

Our Labs package of Canvas Kit tokens, components, and utilities at `@workday/canvas-kit-labs-react`
has **not** undergone a full design and a11y review. Labs serves as an incubator space for new and
experimental code and is analagous to code in alpha.

Breaking changes can be deployed to Labs at any time without triggering a major version update and
may not be subject to the same rigor in communcation and migration strategies reserved for breaking
changes in [Preview](#preview) and [Main](#main).