Component Library migration guide
Preparation
Section titled “Preparation”Before proceeding with the migration, make sure to read the migration overview.
Once you’re ready to migrate, install Cimpress UI in your project by following the installation instructions:
Afterwards, consult this page for guidance on migrating specific components.
Migration guide
Section titled “Migration guide”Changes common to all components
Section titled “Changes common to all components”-
The default font size has increased from 14px to 16px. This change may require adjustments to your project’s layout.
-
Components no longer have built-in outer spacing. Spacing between components should be defined either by the parent component, or through the use of style props.
// Before<TextField /><TextField />// After (spacing defined by parent component)<Stack gap={16}><TextField /><TextField /></Stack>// After (spacing defined using a style prop)<TextField marginBottom={16} /><TextField /> -
classNameandstyleprops have been renamed toUNSAFE_classNameandUNSAFE_stylerespectively. We strongly recommend removing any style overrides. See our styling guide for details.
Accordion
Section titled “Accordion”In most cases, the Accordion component should be migrated to the Disclosure component.
API differences
Section titled “API differences”-
The following props have been renamed:
customOpenbecomesisExpandeddefaultOpenbecomesdefaultExpanded
-
Values for the
variantprop are different:'default'and'ghost'should be replaced with'base''minimal'should be replaced with'subtle'
-
headerStyleandbodyStyleprops are no longer supported, as Cimpress UI doesn’t allow style overrides. -
onCloseandonHeaderClickevent handlers are no longer supported. UseonExpandedChangeto detect when the disclosure expands/collapses. -
titleprop now only accepts string content, and nesting other components is no longer allowed. A restricted set of additional content can be added to the disclosure header using theiconStart,iconEnd,badge, andactionsprops.
Grouping
Section titled “Grouping”Disclosures that form a logical unit should be grouped using the DisclosureGroup component. See disclosure usage guidelines for more information.
In most cases, the Alert component should be migrated to one of the following components:
API differences
Section titled “API differences”-
statusprop has been renamed totone. Most values are the same, with the following exception:'danger'becomes'critical'
-
titleprop now only accepts string content, and nesting other components is no longer allowed. -
There is no
messageprop onAlertnorCallout. Instead, provide the contents as children of the component. Note that nesting other components withinAlert/Calloutis not allowed.// Before<Alert message="My message" />// After<Callout>My message</Callout>In the case of
Callout, you may provide anactionsprop with the buttons that will be displayed at the bottom of the callout.// Before<Alertmessage={<><span>This is a callout with a button.</span><Button>Learn more</Button></>}/>// After<Callout actions={<Button>Learn more</Button>}>This is a callout with a button.</Callout> -
dismissibleprop has been renamed toisDismissible. -
dismissedprop is no longer supported. Use conditional rendering if you want to dismiss the alert/callout programmatically.// Beforeconst [isDismissed, setIsDismissed] = useState(false);return <Alert dismissed={isDismissed} onDismiss={() => setIsDismissed(true)} message="..." />;// Afterconst [isDismissed, setIsDismissed] = useState(false);return isDismissed ? <Callout onDismiss={() => setIsDismissed(true)}>...</Callout> : null;
Breadcrumbs
Section titled “Breadcrumbs”In most cases, the Breadcrumbs component should be migrated to the Breadcrumbs component. Similarly, BreadcrumbItem should be migrated to BreadcrumbItem.
API differences
Section titled “API differences”-
In Component Library,
BreadcrumbItemwas a presentational container that required providing an interactive element (e.g., a button) as its child. In Cimpress UI,BreadcrumbItemis itself interactive, and only accepts string content as children.// Before<BreadcrumbItem><Button href="/">Home</Button></BreadcrumbItem>// After<BreadcrumbItem href="/">Home</BreadcrumbItem> -
activeprop onBreadcrumbItemis no longer supported. The lastBreadcrumbItemwithinBreadcrumbsis now assumed to refer to the current page, and it becomes non-interactive.
Button
Section titled “Button”In most cases, the Button component should be migrated to one of the following components:
Button/IconButton(if used to perform an action)LinkButton/IconLinkButton(if used to perform navigation)ToggleButton/ToggleIconButton(if used to toggle an option on and off, or to select an option from a set)
API differences
Section titled “API differences”-
Some values for the
variantprop are different:'default'becomes'secondary''link'becomes'tertiary''anchor'is no longer supported - choose a different variant or convert the button to a link
-
colorprop has been renamed totone. Values are renamed as follows:'primary'becomes'base''danger'becomes'critical'
-
Values for the
sizeprop have been renamed:'sm'becomes'small''default'becomes'medium''lg'becomes'large'
-
The following props have been renamed:
disabledbecomesisDisabledblockLevelbecomesfullWidthonClickbecomesonPressonMouseEnterbecomesonHoverStartonMouseLeavebecomesonHoverEnd
-
childrenprop now only accepts string content, and nesting other components is no longer allowed. If usingButtonorLinkButton, you can add additional icons to the button using theiconStartandiconEndprops.// Before<Button><IconAdd /><span>Add</span></Button>// After<Button iconStart={<IconAdd />}>Add</Button> -
Objects provided as arguments to
onPress,onHoverStart, andonHoverEndhave a different structure. If you relied on the previous structure, get in touch with us and let us know your use case.
Usage as toggles
Section titled “Usage as toggles”Buttons were previously used as toggles by changing between the primary and secondary variants depending on whether the button was in the “on” or “off” state. This is now disallowed, and such buttons should be replaced with the ToggleButton component.
// Before<Button variant={isBold ? 'primary' : 'secondary'}>Bold</Button>
// After<ToggleButton isSelected={isBold}>Bold</ToggleButton>Bear in mind that for this use case the button label MUST remain the same in both the “on” and “off” states.
Multiple related toggle buttons should be grouped using the ToggleButtonGroup component. See toggle button usage guidelines for details.
Checkbox
Section titled “Checkbox”In most cases, the Checkbox component should be migrated to the Checkbox component.
API differences
Section titled “API differences”-
The following props have been renamed:
checkedbecomesisSelectedindeterminatebecomesisIndeterminatedisabledbecomesisDisabled
-
In Component Library, a checkbox with both
checkedandindeterminateprops would render as checked. In Cimpress UI, a checkbox with bothisSelectedandisIndeterminatewill now render as indeterminate. -
There is no
labelprop onCheckbox. Instead, provide the checkbox label as children of theCheckboxcomponent. Note that nesting other components withinCheckboxis not allowed.// Before<Checkbox label="I agree to the terms and conditions" />// After<Checkbox>I agree to the terms and conditions</Checkbox>If the checkbox is rendered without a visible label, a hidden label must still be provided to identify the checkbox’s purpose to assistive technologies. This can be done using the
aria-labeloraria-labelledbyprops. -
onChangeevent handler now accepts a single boolean argument specifying whether the checkbox is selected.// Before<Checkboxlabel="..."onChange={(e) => console.log(`Checkbox is ${e.target.checked ? 'selected' : 'not selected'}`)}/>// After<CheckboxonChange={(isSelected) => console.log(`Checkbox is ${isSelected : 'selected' : 'not selected'}`)}>...</Checkbox> -
whiteBackgroundprop is no longer supported. The checkbox icon will always render with a white background. -
inlineprop is no longer supported. Layout should be dictated by the parent element. If usingCheckboxGroup, you can passdirection="horizontal"to stack checkboxes horizontally instead of vertically. -
payloadprop is no longer supported.
Grouping
Section titled “Grouping”Related checkboxes should be grouped using the CheckboxGroup component. See checkbox usage guidelines for more information.
In most cases, the Copy component should be migrated to one of the following components:
CopyButton(if used as a button)CopyInline(if used inline)
API differences
Section titled “API differences”-
variantprop has been repurposed, and no longer allows to switch between the “button” and “inline” versions of the Copy component. Instead, migrate to an appropriate component from the list above.If migrating to
CopyButton, thevariantprop can be used to switch between a secondary and tertiary button variants.If migrating to
CopyInline, thevariantprop can be used to pick a typography variant that the component is rendered with. -
hoverTextprop has been renamed todescriptionon theCopyInlinecomponent. It is not supported on theCopyButtoncomponent. -
onClickevent handler has been renamed toonCopy. It doesn’t accept any arguments. -
successMessageprop is no longer supported. Success and failure messages are exposed in the localization system ascopyToClipboard.successandcopyToClipboard.failurerespectively. -
durationprop is no longer supported. The message duration is not customizable. -
If migrating to
CopyButton: a textual label is required to identify the button’s purpose to assistive technologies. This can be a visible label (using thechildrenprop) or a hidden one (using thearia-labeloraria-labelledbyprops). -
If migrating to
CopyInline: thevalueprop is no longer supported. The copied text will be the same as the displayed text provided using thechildrenprop.
Drawer
Section titled “Drawer”In most cases, the Drawer component should be migrated to the Drawer component.
API differences
Section titled “API differences”-
In Component Library, a button that opens a drawer had to be manually wired with the drawer. In Cimpress UI, the trigger button can be automatically associated with a drawer. To do this, wrap both the trigger button and the drawer itself in the
<DrawerRoot>component. Make sure that the trigger button is provided first.// Beforeconst [isDrawerOpen, setIsDrawerOpen] = useState(false);return (<><Button onClick={() => setIsDrawerOpen(true)}>Open drawer</Button><Drawer show={isDrawerOpen}>{/* Drawer content */}</Drawer></>);// Afterreturn (<DrawerRoot><Button>Open drawer</Button><Drawer>{/* Drawer content */}</Drawer></DrawerRoot>); -
Drawercomponent only allows two child components:DrawerBodyandDrawerActions.DrawerBodyshould wrap the main content of the drawer, andDrawerActionsshould wrap the actions that the user can take within the drawer. These actions will be rendered at the bottom of the drawer.This also means that the
footerprop is no longer supported, as the footer is reserved for actions rendered byDrawerActions.// Before<Drawer footer={<Button>Action</Button>}>Drawer content</Drawer>// After<Drawer><DrawerBody>Drawer content</DrawerBody><DrawerActions><Button>Action</Button></DrawerActions></Drawer> -
The following props have been renamed:
showbecomesisOpencloseOnOutsideClickbecomesisDismissible
-
headerprop has been renamed totitle, and it now only accepts string content. Nesting other components is not allowed. -
sizeprop now accepts one of three values:'small','medium', or'large'. -
wrapperStyle,headerStyle,bodyStyle, andfooterStyleprops are no longer supported, as Cimpress UI doesn’t allow style overrides. -
onRequestHideevent handler is no longer supported. UseonOpenChangeto detect when the drawer closes. -
autoResizeprop is no longer supported, as drawers have fixed sizes now. -
positionandzIndexprops are no longer supported. -
If the drawer is not dismissible, you must provide a way for the user to close the drawer. This can be done by passing a function as
childrento theDrawercomponent, and using theclosefunction provided as an argument to that function.// Beforeconst [isDrawerOpen, setIsDrawerOpen] = useState(true);return (<Drawer closeOnOutsideClick={false} footer={<Button onClick={() => setIsDrawerOpen(false)}>Close</Button>}>Drawer content</Drawer>);// After (uncontrolled)return (<Drawer isDismissible={false}>{({ close }) => (<><DrawerBody>Drawer content</DrawerBody><DrawerActions><Button onPress={close}>Close</Button></DrawerActions></>)}</Drawer>);// After (controlled)const [isDrawerOpen, setIsDrawerOpen] = useState(true);return (<Drawer isOpen={isDrawerOpen} isDismissible={false}><DrawerBody>Drawer content</DrawerBody><DrawerActions><Button onPress={() => setIsDrawerOpen(false)}>Close</Button></DrawerActions></Drawer>);
Dropdown
Section titled “Dropdown”In most cases, the Dropdown component should be migrated to the Menu component.
API differences
Section titled “API differences”-
The menu trigger button needs to be explicitly provided now. To do this, wrap both the trigger button and the menu itself in the
<MenuRoot>component. Make sure that the trigger button is provided first.This also means that the
titleprop is no longer supported, and you should provide the label directly on the trigger button.// Before<Dropdown title="Menu">{/* Dropdown content */}</Dropdown>// After<MenuRoot><Button iconEnd={<IconChevronDown />}>Menu</Button><Menu>{/* Menu content */}</Menu></MenuRoot> -
In Component Library,
Dropdownallowed all kinds of child elements within the dropdown list. In Cimpress UI, only three components are allowed as children ofMenu:MenuItem- renders an interactive menu itemMenuSection- groups menu items into sectionsDivider- renders a divider between menu items/sections
The
MenuItemcomponent is itself interactive, and doesn’t allow nesting other components within it. A restricted set of additional content can be added to the menu item using thedescriptionandiconprops.// Before<Dropdown title="Menu"><button>Option 1</button><button>Option 2</button><hr /><a href="/">Go to homepage</a></Dropdown>// After<MenuRoot><Button iconEnd={<IconChevronDown />}>Menu</Button><Menu><MenuItem>Option 1</MenuItem><MenuItem>Option 2</MenuItem><Divider /><MenuItem href="/">Go to homepage</MenuItem></Menu></MenuRoot>To detect when a menu item has been pressed, use the
onActionprop on eitherMenuItemorMenu:// Before<Dropdown title="Menu"><button onClick={() => console.log('Option 1 pressed')}>Option 1</button><button onClick={() => console.log('Option 2 pressed')}>Option 2</button></Dropdown>// After (with `onAction` on each menu item)<MenuRoot><Button>...</Button><Menu><MenuItem onAction={() => console.log('Option 1 pressed')}>Option 1</MenuItem><MenuItem onAction={() => console.log('Option 2 pressed')}>Option 2</MenuItem></Menu></MenuRoot>// After (with `onAction` on Menu)<MenuRoot><Button>...</Button><Menu onAction={(id) => console.log(`${id} pressed`)}><MenuItem id="option-1">Option 1</MenuItem><MenuItem id="option-2">Option 2</MenuItem></Menu></MenuRoot>Note that when using
onActionon theMenucomponent, all menu items must have anidprop. -
disabledprop is no longer supported. Use theisDisabledprop on the trigger button instead. -
variantprop is no longer supported. You can customize the menu trigger button through its own props. -
asprop is no longer supported.
GlobalStyles
Section titled “GlobalStyles”The GlobalStyles component was used to inject global CSS-in-JS styles into the application. Cimpress UI uses a different approach for CSS, so the GlobalStyles component is no longer needed.
If you’re fully migrating to Cimpress UI, you can safely remove the GlobalStyles component from your component tree. If you’re using Component Library together with Cimpress UI, you should continue to render GlobalStyles as before - it will not impact Cimpress UI components.
In most cases, the Label component should be migrated to the Badge component.
API differences
Section titled “API differences”-
statusprop has been renamed totone. Most values are the same, with the following exceptions:'primary'and'default'become'base''danger'becomes'critical'
-
Values for the
sizeprop have been renamed:'sm'becomes'small''default'becomes'medium''lg'becomes'large'
-
There is no
textprop onBadge. Instead, provide the badge contents as children of theBadgecomponent. Note that nesting other components withinBadgeis not allowed.// Before<Label text="Info" />// After<Badge>Info</Badge>
In most cases, the Modal component should be migrated to the ModalDialog component.
API differences
Section titled “API differences”-
In Component Library, a button that opens a modal had to be manually wired with the modal. In Cimpress UI, the trigger button can be automatically associated with a modal dialog. To do this, wrap both the trigger button and the modal dialog itself in the
<DialogRoot>component. Make sure that the trigger button is provided first.// Beforeconst [isModalOpen, setIsModalOpen] = useState(false);return (<><Button onClick={() => setIsModalOpen(true)}>Open modal</Button><Modal show={isModalOpen}>{/* Modal content */}</Modal></>);// Afterreturn (<DialogRoot><Button>Open modal dialog</Button><ModalDialog>{/* Modal dialog content */}</ModalDialog></DialogRoot>); -
ModalDialogcomponent only allows two child components:ModalDialogBodyandModalDialogActions.ModalDialogBodyshould wrap the main content of the modal, andModalDialogActionsshould wrap the actions that the user can take within the modal. These actions will be rendered at the bottom of the modal dialog.This also means that the
footerprop is no longer supported, as the footer is reserved for actions rendered byModalDialogActions.// Before<Modal footer={<Button>Action</Button>}>Modal content</Modal>// After<ModalDialog><ModalDialogBody>Modal dialog content</ModalDialogBody><ModalDialogActions><Button>Action</Button></ModalDialogActions></ModalDialog> -
The following props have been renamed:
showbecomesisOpencloseOnOutsideClickbecomesisDismissible
-
Values for the
sizeprop have been renamed:'md'becomes'small''lg'becomes'medium''xl'becomes'large'
-
titleprop now only accepts string content, and nesting other components is not allowed. -
wrapperStyleprop is no longer supported, as Cimpress UI doesn’t allow style overrides. -
onRequestHideevent handler is no longer supported. UseonOpenChangeto detect when the modal dialog closes. -
statusprop is no longer supported. Use theUNSTABLE_AlertDialogcomponent if you need an overlay with a specific tone. -
closeButtonprop is no longer supported. If the modal dialog is dismissible, a close button will be rendered automatically. If the modal dialog is not dismissible, you must provide a way for the user to close the modal dialog. This can be done by passing a function aschildrento theModalDialogcomponent, and using theclosefunction provided as an argument to that function.// Before<Modal closeOnOutsideClick={false} closeButton={true}>Modal content</Modal>// After<ModalDialog isDismissible={false}>{({ close }) => (<><ModalDialogBody>Modal content</ModalDialogBody><ModalDialogActions><Button onPress={close}>Close</Button></ModalDialogActions></>)}</ModalDialog>
NavTab
Section titled “NavTab”In most cases, the NavTab component should be migrated to the LinkTabs component. Similarly, the NavTabItem component should be migrated to the LinkTab component.
API differences
Section titled “API differences”-
In Component Library,
NavTabItemallowed all kinds of child elements within the tab. In Cimpress UI, theLinkTabcomponent is itself interactive, and doesn’t allow nesting other components within it. A restricted set of additional content can be added to the tab using theiconStartandbadgeprops.// Before<NavTab><NavTabItem><button>Option 1</button></NavTabItem><NavTabItem><button>Option 2</button></NavTabItem></NavTab>// After<LinkTabs><LinkTab>Option 1</LinkTab><LinkTab>Option 2</LinkTab></LinkTabs> -
verticalprop is no longer supported. -
disabledprop onNavTabItemhas been renamed toisDisabledonLinkTab. -
activeprop onNavTabItemis no longer supported. UsecurrentHrefordefaultHrefprop onLinkTabsinstead, in combination withhrefon eachLinkTab.// Beforeconst [selectedTab, setSelectedTab] = useState('tab-1');return (<NavTab><NavTabItem active={selectedTab === 'tab-1'}><button onClick={() => setSelectedTab('tab-1')}>Tab 1</button></NavTabItem><NavTabItem active={selectedTab === 'tab-2'}><button onClick={() => setSelectedTab('tab-2')}>Tab 2</button></NavTabItem></NavTab>);// Afterconst [selectedTab, setSelectedTab] = useState('#tab-1');return (<LinkTabs currentHref={selectedTab} onHrefChange={setSelectedTab}><LinkTab href="#tab-1">Tab 1</LinkTab><LinkTab href="#tab-2">Tab 2</LinkTab></LinkTabs>); -
LinkTabsnow requires a hidden label to provide context about its purpose to assistive technologies. This label can be provided using thearia-labeloraria-labelledbyprops.
In most cases, the Radio component should be migrated to the Radio component.
API differences
Section titled “API differences”-
Radios cannot be used on their own, and must always be wrapped in a
<RadioGroup>component. -
disabledprop has been renamed toisDisabled. -
valueprop is now required.valuemust be unique across all radios within aRadioGroup. This prop only accepts string content. -
nameprop is no longer supported. Use thenameprop onRadioGroupinstead. -
checkedprop is no longer supported. To make a radio button selected, provide itsvalueto thevalue/defaultValueprop onRadioGroup.// Before<Radio value="option-1" /><Radio value="option-2" checked />// After<RadioGroup value="option-2"><Radio value="option-1">...</Radio><Radio value="option-2">...</Radio></RadioGroup> -
onCheckevent handler is no longer supported. UseonChangeonRadioGroupinstead. -
There is no
labelprop onRadio. Instead, provide the radio label as children of theRadiocomponent. Note that nesting other components withinRadiois not allowed.// Before<Radio label="Option 1" />// After<Radio>Option 1</Radio>If the radio is rendered without a visible label, a hidden label must still be provided to identify the radio’s purpose to assistive technologies. This can be done using the
aria-labeloraria-labelledbyprops. -
backgroundColorprop is no longer supported. The radio indicator will always render with a white background. -
onFocusandonBlurevent handlers are no longer supported.
RadioGroup
Section titled “RadioGroup”In most cases, the RadioGroup component should be migrated to the RadioGroup component.
API differences
Section titled “API differences”-
The following props have been renamed:
valueSelectedbecomesvaluedefaultSelectedbecomesdefaultValue
Both of these props now only accept string content.
-
The
inlineprop has been replaced with adirectionprop. This prop accepts one of two values:'vertical'and'horizontal'.// Before<RadioGroup inline>...</RadioGroup>// After<RadioGroup direction="horizontal">...</RadioGroup> -
onChangeevent handler now accepts a single string argument - the value of the currently selected option.// Before<RadioGrouponChange={(e, value) => console.log(`Selected option: ${value}`)}>...</RadioGroup>// After<RadioGrouponChange={(value) => console.log(`Selected option: ${value}`)}>...</RadioGroup> -
RadioGroupnow requires a label to provide context about its purpose. This can either be a visible label (provided using thelabelprop) or a hidden one (provided using thearia-labeloraria-labelledbyprops).
Select
Section titled “Select”In most cases, the Select component should be migrated to one of the following components:
Select(for single selection without filtering)ComboBox(for single selection with filtering)TagField(for multiple selection with filtering)
API differences
Section titled “API differences”-
isMultiandisSearchableprops are no longer supported. Instead, choose an appropriate component to migrate to from the list above. -
The following props have been renamed:
requiredbecomesisRequiredonChangebecomesonSelectionChangehelpTextbecomesdescription
-
descriptionandplaceholderprops now only accept string content, and nesting other components is not allowed. -
statusprop is no longer supported. To show an error state, use theisInvalidprop. -
optionsprop is no longer supported. Options can now be provided as a static list using thechildrenprop, or as a dynamic list using theitemsprop.When providing a static list, use the appropriate
<...Item>and<...Section>components. For example, if migrating to aComboBoxcomponent, you would useComboBoxItemandComboBoxSectioncomponents to define your list. You can also use the<Divider>component to render a divider between items.// Beforeconst options = [{ label: 'Option 1', value: 'option-1' },{ label: 'Option 2', value: 'option-2' },];return <Select options={options} onChange={(option) => console.log(`${option.value} selected`)} />;// Afterreturn (<Select onSelectionChange={(id) => console.log(`${id} selected`)}><SelectItem id="option-1">Option 1</SelectItem><SelectItem id="option-2">Option 2</SelectItem></Select>);When providing a dynamic list, use the
itemsprop to provide the array describing your list. You will also have to instruct the component how to render your list items by providing a mapping function using thechildrenprop.// Beforeconst options = [{ label: 'Option 1', value: 'option-1' },{ label: 'Option 2', value: 'option-2' },];return <Select options={options} />;// Afterconst items = [{ id: 'option-1', label: 'Option 1' },{ id: 'option-2', label: 'Option 2' },];return <Select items={items}>{(item) => <SelectItem>{item.label}</SelectItem>}</Select>;See our collection components guide for more information and examples.
-
valueanddefaultValueprops have been renamed toselectedKeyanddefaultSelectedKeyrespectively. These props now accept the ID of the selected item instead of the selected item itself. ForTagField, the prop names are pluralized, and they accept a set of IDs. -
onSelectionChangeevent handler now accepts a single argument: the ID of the selected item (a set of IDs forTagField). -
containerClassNameprop is no longer supported, as Cimpress UI doesn’t allow style overrides. -
For imperative actions like focusing or text selection, use the
apiRefprop instead ofref.// Beforeconst ref = useRef<HTMLElement>(null);return (<Select ref={ref} /><Button onClick={() => ref.current?.focus()}>Focus</Button>);// Afterconst apiRef = useRef<SelectApi>(null);return (<Select apiRef={apiRef} /><Button onPress={() => apiRef.current?.focus()}>Focus</Button>); -
The old
Selectcomponent exposed implementation details of an external library, and most of those props are no longer supported. Read through the API documentation of your chosen replacement component to see its capabilities and to find alternatives for props not listed in this guide. -
Select,ComboBox, andTagFieldall require a label to provide context about their purpose. This can either be a visible label (provided using thelabelprop) or a hidden one (provided using thearia-labeloraria-labelledbyprops).
SelectWrapper
Section titled “SelectWrapper”The SelectWrapper component was used to provide Component Library styling to forks of the react-select component. This is no longer supported in Cimpress UI, and usages of SelectWrapper should be migrated to one of the following components:
Select(for single selection without filtering)ComboBox(for single selection with filtering)TagField(for multiple selection with filtering)
Follow the Select migration guide together with the usage guidelines linked above to aid the migration.
Spinner
Section titled “Spinner”In most cases, the Spinner component should be migrated to the Spinner component.
API differences
Section titled “API differences”-
Spinnernow requires a label to provide context about its purpose. This can either be a visible label (provided using thelabelprop) or a hidden one (provided using thearia-labeloraria-labelledbyprops). -
fullPageprop is no longer supported. An equivalent layout can be achieved by rendering a spinner in the center of an absolutely positioned container. -
duration,offset, andhandleOffsetprops are no longer supported. Customization of the spinner animation is not allowed.
TabCard
Section titled “TabCard”In most cases, the TabCard component should be migrated to the Tabs component.
API differences
Section titled “API differences”-
There are now multiple components that need to be composed to render tabs.
// Before<TabCard tabs="..." />// After<Tabs><TabList>...</TabList><TabPanels>...</TabPanels></Tabs> -
tabsprop is no longer supported. Tabs can now be provided as a static or dynamic list.When providing a static list, use the
<Tab>component to define a tab inside<TabList>, and the<TabPanel>component to define the tab contents inside<TabPanels>. You will also need to associate each<Tab>with its<TabPanel>by providing the same value for theidprop.// Beforeconst tabs = [{ name: 'Tab 1', block: 'Content for tab 1' },{ name: 'Tab 2', block: 'Content for tab 2' },];return <TabCard tabs={tabs} />;// Afterreturn (<Tabs><TabList><Tab id="tab-1">Tab 1</Tab><Tab id="tab-2">Tab 2</Tab></TabList><TabPanels><TabPanel id="tab-1">Content for tab 1</TabPanel><TabPanel id="tab-2">Content for tab 2</TabPanel></TabPanels></Tabs>);When providing a dynamic list, use the
itemsprop on<TabList>and<TabPanels>to provide the array describing your list. You will also have to instruct the components how to render your list items by providing a mapping function using thechildrenprop.// Beforeconst tabs = [{ name: 'Tab 1', block: 'Content for tab 1' },{ name: 'Tab 2', block: 'Content for tab 2' },];return <TabCard tabs={tabs} />;// Afterconst tabs = [{ id: 'tab-1', title: 'Tab 1', content: 'Content for tab 1' },{ id: 'tab-2', title: 'Tab 2', content: 'Content for tab 2' },];return (<Tabs><TabList items={tabs}>{(item) => <Tab>{item.title}</Tab>}</TabList><TabPanels items={tabs}>{(item) => <TabPanel>{item.content}</TabPanel>}</TabPanels></Tabs>);See our collection components guide for more information and examples.
-
selectedIndexprop has been renamed toselectedKey. This prop now accepts the ID of the selected tab instead of its index in thetabsarray.// Beforeconst tabs = [{ name: 'Tab 1', block: 'Content for tab 1' },{ name: 'Tab 2', block: 'Content for tab 2' },];return <TabCard tabs={tabs} selectedIndex={0} />;// Afterconst tabs = [{ id: 'tab-1', title: 'Tab 1', content: 'Content for tab 1' },{ id: 'tab-2', title: 'Tab 2', content: 'Content for tab 2' },];return <Tabs selectedKey="tab-1">...</Tabs>;A new
defaultSelectedKeyprop was also added to allow for uncontrolled usage. -
onSelectevent handler has been renamed toonSelectionChange. It now accepts a single argument: the ID of the selected tab.// Beforeconst tabs = [{ name: 'Tab 1', block: 'Content for tab 1' },{ name: 'Tab 2', block: 'Content for tab 2' },];return <TabCard tabs={tabs} onSelect={(e, selectedIndex) => console.log(`Selected tab index: ${selectedIndex}`)} />;// Afterconst tabs = [{ id: 'tab-1', title: 'Tab 1', content: 'Content for tab 1' },{ id: 'tab-2', title: 'Tab 2', content: 'Content for tab 2' },];return <Tabs onSelectionChange={(selectedId) => console.log(`Selected tab ID: ${selectedId}`)}>...</Tabs>; -
Tab footers are no longer supported.
-
The
hrefattribute on tabs is no longer supported. If you’re using tabs as your application’s primary method of navigation, we recommend using the<TopNav>component instead. For other use cases, you can use the<LinkTabs>component instead. -
Tabsnow requires a hidden label to provide context about its purpose to assistive technologies. This label can be provided using thearia-labeloraria-labelledbyprops.
In most cases, the Tag component should be migrated to the Tag component.
API differences
Section titled “API differences”-
Tags cannot be used on their own, and must always be wrapped in a
<TagGroup>component. A standalone<Tag>component will throw an error at runtime. -
Values for the
sizeprop are different:'sm'and'default'should be replaced with'medium''lg'should be replaced with'large'
-
There is no
labelprop onTag. Instead, provide the tag contents as children of theTagcomponent. Note that nesting other components withinTagis not allowed.
// Before<Tag label="My tag" />
// After<Tag>My tag</Tag>Additionally, in Component Library it was possible to omit label if value was provided. This is no longer the case, and tag content must always be explicitly provided.
-
valueprop has been renamed toid. Note that only string content is accepted, and nesting other components is not allowed. -
variantprop is no longer supported. -
removableandonRemoveClickprops are no longer supported. To allow tags to be removed, use theonRemoveevent handler on the parent<TagGroup>component.
TextArea
Section titled “TextArea”In most cases, the TextArea component should be migrated to the TextArea component.
API differences
Section titled “API differences”-
The following props have been renamed:
requiredbecomesisRequireddisabledbecomesisDisabledhelpTextbecomesdescription
-
descriptionprop now only accepts string content, and nesting other components is not allowed. -
statusprop is no longer supported. To show an error state, use theisInvalidprop. -
inputStyleprop is no longer supported, as Cimpress UI doesn’t allow style overrides. -
rightAddonprop is no longer supported. Additional elements should be rendered outside of the text area. -
typeprop is no longer supported, as it never had any effect onTextArea. -
patternprop is no longer supported. Use thepatternprop onTextFieldinstead. -
For imperative actions like focusing or text selection, use the
apiRefprop instead ofref.// Beforeconst ref = useRef<HTMLTextAreaElement>(null);return (<TextArea ref={ref} /><Button onClick={() => ref.current?.focus()}>Focus</Button>);// Afterconst apiRef = useRef<TextAreaApi>(null);return (<TextArea apiRef={apiRef} /><Button onPress={() => apiRef.current?.focus()}>Focus</Button>); -
onChangeevent handler now accepts a single string argument - the current contents of the text area.// Before<TextArealabel="..."onChange={(e) => console.log(`Input value: ${e.target.value}`)}/>// After<TextArealabel="..."onChange={(value) => console.log(`Input value: ${value}`)}/> -
onClickevent handler is no longer supported. UseonFocusand/oronChangeto detect when the user interacts with the field. -
In Component Library,
TextArearequired either alabelor aplaceholderto be provided. In Cimpress UI, a label is now required to provide context about the field’s purpose. This can either be a visible label (provided using thelabelprop) or a hidden one (provided using thearia-labeloraria-labelledbyprops). Theplaceholderprop is independent fromlabel, and is optional.
TextField
Section titled “TextField”In most cases, the TextField component should be migrated to one of the following components:
TextField(for single-line free text input)NumberField(for numeric input)SearchField(for search phrase input)
API differences
Section titled “API differences”-
The following props have been renamed:
requiredbecomesisRequireddisabledbecomesisDisabledhelpTextbecomesdescription
-
descriptionprop now only accepts string content, and nesting other components is not allowed. -
statusprop is no longer supported. To show an error state, use theisInvalidprop. -
inputStyleprop is no longer supported, as Cimpress UI doesn’t allow style overrides. -
rightAddonprop is no longer supported. Use thesuffixprop to render a piece of text or a single icon at the end of the input field. Interactive elements should be rendered outside of the field. -
For imperative actions like focusing or text selection, use the
apiRefprop instead ofref.// Beforeconst ref = useRef<HTMLInputElement>(null);return (<TextField ref={ref} /><Button onClick={() => ref.current?.focus()}>Focus</Button>);// Afterconst apiRef = useRef<TextFieldApi>(null);return (<TextField apiRef={apiRef} /><Button onPress={() => apiRef.current?.focus()}>Focus</Button>); -
onChangeevent handler now accepts a single string argument - the current contents of the input field.// Before<TextFieldlabel="..."onChange={(e) => console.log(`Input value: ${e.target.value}`)}/>// After<TextFieldlabel="..."onChange={(value) => console.log(`Input value: ${value}`)}/> -
onInputevent handler is no longer supported, useonChangeinstead. -
onClickevent handler is no longer supported. UseonFocusand/oronChangeto detect when the user interacts with the field. -
In Component Library,
TextFieldrequired either alabelor aplaceholderto be provided. In Cimpress UI, a label is now required to provide context about the field’s purpose. This can either be a visible label (provided using thelabelprop) or a hidden one (provided using thearia-labeloraria-labelledbyprops). Theplaceholderprop is independent fromlabel, and is optional.
Tooltip
Section titled “Tooltip”In most cases, the Tooltip component should be migrated to one of the following components:
Tooltip(if it contains no interactive content, and is shown on hover/focus)Popover(if it contains interactive content, and is shown on press)
API differences
Section titled “API differences”-
The following props have been renamed:
showbecomesisOpendirectionbecomesplacement
-
tooltipStyle,tooltipInnerStyle, andcontainerClassNameprops are no longer supported, as Cimpress UI doesn’t allow style overrides. -
constraintsprop is no longer supported, as it was exposing an implementation detail of an external library that is no longer being used. -
variant,variety,delayandoutsideClickIgnoreClassprops are no longer supported. -
onClickOutsideprop is no longer supported. UseonOpenChangeevent handler to detect when the overlay closes. -
If migrating to
Tooltip:contentsprop has been renamed tolabel, and it now only accepts string content. Nesting other components is not allowed. -
If migrating to
Popover: the trigger button and the popover contents are now provided differently. Provide popover contents as children of the<Popover>component, and wrap both the trigger button and the popover itself in the<PopoverRoot>component. Make sure that the trigger button is provided first.This also means that the
contentsprop is no longer supported.// Before<Tooltip variant="popover" contents={<p>This is a <b>popover</b>!</p>}><button>Show popover</button></Tooltip>// After<PopoverRoot><Button>Show popover</Button><Popover><p>This is a <b>popover</b>!</p></Popover></PopoverRoot> -
If migrating to
Popover: thePopovercomponent requires a title to identify its purpose to assistive technologies. This can either be a visible title (provided using thetitleprop) or a hidden one (provided using thearia-labeloraria-labelledbyprops).