Canvas v9 Upgrade Guide
Upgrade Overview
The table below contains a high-level overview of the updates that rolled out as part of the v9 release. The impact for developers is defined as follows:
- None: inapplicable to the role or no actions are required for users to adopt the change; Updates will be applied automatically once users upgrade to Canvas Kit v9
- Low: minor changes are required for users to adopt the change
- Medium: a moderate amount of changes are required for users to adopt the change, such as switching out UI elements
- High: a large amount of changes are required for users to adopt the change, requiring teams to make major development decisions
Change | Short Description | Developer Impact |
---|---|---|
Canvas Design System Site Versioning | Versioning will be available for documentation on the Canvas Design System site, corresponding to each major Canvas release | None |
Depth Token Modifications | Depth tokens will be modified to reduce the harshness/contrast of depth against backgrounds | None |
Table Refactoring | A new Table component will be released in the Preview package with increased flexibility and updated styling | None |
New Combobox Sub-system | A new Combobox sub-system will be released to help developers build components and features with Combobox like autocomplete and Select | None |
Layout Component Removal | The Layout component will be removed | Medium |
Drawer Component Removal | The Drawer component in the Labs package will be removed | Medium |
Stack Component Removals | The Stack, VStack, HStack components will all be removed | Low |
Default Button Type Modifications | The default button type for all Canvas buttons will be updated from submit to button | Medium |
useTheme Updates | A fix will be implemented to prevent useTheme hook from generating an error when the styled function is used without a predefined theme | Low |
useThemedRing Promotion | The useThemedRing hook will be promoted to the Main package | None |
useThemeRTL Deprecation | The useThemeRTL hook will be deprecated in Canvas v9, but will still be available for use | None |
useCanvasTheme and getCanvasTheme Removal | useCanvasTheme and getCanvasTheme will be removed in favor of useTheme and getTheme , respectively | Low |
Canvas Kit’s TS Compiler Target Updates | The TS compiler target will be updated from ES5 to ES2019. This will significantly decrease the Canvas Kit bundle size | None |
Toast Component Promotion | The Toast component in the Labs package will be promoted to the Main package, replacing the current Toast component in Main | None |
Enhanced QA & Testing Processes | Additional tests will be added to expand testing across different screen sizes and modality as well as expand visual regression testing | None |
For a deeper look into the v9 upgrade, check out the guide on the For Developers tab.
This guide contains an overview of the changes in Canvas Kit v9. Please reach out if you have any questions.
- Codemod
- New Components
- Updated Terms
- Removals
- Deprecations
- Token Updates
- Component Updates
- Utility Updates
- Glossary
Codemod
We've provided a 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, 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
.
> 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.
> 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 to the Preview
package. Table
is a compound component that is used to present information in a two-dimensional
table comprised of rows and
columns of cells containing data.
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
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
toDeprecatedComponenntName
. As of 9.0, we longer do this.
- Previously, we also added "Deprecated" to a component name. For example, from
- Deprecate/Deprecation: We add the @deprecated tag
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.
"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
We've removed the Drawer
component (for reference, see the
Drawer
from v8). Please
use the SidePanel
in Preview instead.
Note: The
SidePanel
in Main will eventually be replaced with theSidePanel
in Preview. We recommend you use theSidePanel
in Preview until then.
Layout and Column
PR: #2018
We've removed the Layout
and Column
components (for reference, see
Column and Layout
from v8). Please use 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 for examples of how to implement common
layouts using Grid
.
composeModelHooks
PR: #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
We've removed the Stack
, HStack
, and VStack
components (for reference, see
Stack
from v8). Please use Flex
instead. Flex
supports the same consistent
spacing between its elements via the gap
prop (analogous to the spacing
prop from Stack
).
// v8<Stack spacing="s">...</Stack>// v9<Flex gap="s">...</Flex>
The orientation of VStack
elements can be replicated with Flex
using flexDirection
.
// 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 oldspacing
prop fromStackProps
to thegap
prop fromFlexProps
.
focusRing
PR: #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
We've removed useCanvasTheme
and getCanvasTheme
. Please use useTheme
and getTheme
instead.
Deprecations
We add the @deprecated 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
We've deprecated useThemeRTL
from Labs. Although you may still use this utility, we
recommend using
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:
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.
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
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
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"
.
This affects all buttons which extend BaseButton
:
PrimaryButton
SecondaryButton
TertiaryButton
DeleteButton
ToolbarDropdownButton
andToolbarIconButton
Pill
andPill.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 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
We've promoted Toast
from Labs to Main. It replaces the Toast
that was
previously in Main (for reference, see
Toast
in
Main from v8).
Toast
is a compound component
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
.
// 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 to use the compound
component API of the new Toast
in Main. mode
will be set to dialog
if the Toast
previously used actionText
or onActionClick
. The codemod will also update imports from the
Labs Toast
to instead import from Main.
Note: You will manually need to set
mode
toalert
if yourToast
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:
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
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
We've promoted useThemedRing
from Labs to 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 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. Occasionally, a component with the same name will exist in both Main and Preview (for example, see Segmented Control in Preview and Main). In these cases, Preview serves as a staging ground for an improved version of the component with a different API. The component in 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 and Main.
Can't Find What You Need?
Check out our FAQ section which may help you find the information you're looking for.
FAQ Section