iTwinUI react v3 migration guide - iTwin/iTwinUI GitHub Wiki
To help with the migration (for breaking changes), we also provide a migration tool that scans your project repo for old code and runs automated codemods.
Download options:
- Clone iTwinUI-migration-tool GitHub repo (recommended)
- Download zip file (version: 08 May 2025) with the tool (for users outside the iTwin GitHub org)
This page documents all breaking changes in @itwin/itwinui-react@^3.0.0. Make sure to install the latest 3.x version and resolve any version conflicts.
Also see @itwin/[email protected] migration guide.
- #1389: iTwinUI is now ESM-first and correctly supports both ESM and CJS environments.
-
#1412: All styles have been wrapped inside a cascade layer named
itwinui. See the styling documentation for more. - #1583: Bumped minimum required react version to 17. If you're still on react 16, please update to react 17 (which has no breaking changes).
-
#1298: Most components are now polymorphic (support
asprop), spread their rest props, and forward their refs. -
#1346: The build now targets
es2020instead ofes2018. As a result, you might need to update some of your build tools (e.g. babel).
-
#1302: The dependencies on
@itwin/itwinui-cssand@itwin/itwinui-variableshave been removed. This means@itwin/itwinui-reactwill bring its own stylesheet. - #1331, #1506: The dependency on tippy.js has been removed in favor of floating ui. While the basic usage is unchanged, all advanced props from tippy are no longer available. Components affected: Tooltip, Select, ComboBox, DropdownMenu, DropdownButton, SplitButton.
-
#1514: The dependency on
@types/react-tablehas been removed. See:Tablesection.
-
#1265: Removed the deprecated
useThemehook.<ThemeProvider>is now always required to be wrapped around every tree within which iTwinUI components are used.+ <ThemeProvider> <App /> + </ThemeProvider>
Note: This doesn't mean that you need to wrap every single component. The important thing is that there is always a
ThemeProvideravailable at some point when you traverse up the tree from an iTwinUI component. If not found, an error will be thrown. The easiest way to do this is by adding aThemeProviderin your top-level entrypoint. -
#1478:
ThemeProvidernow defaults thethemevalue to"inherit"(previously"light"), while still using"light"as fallback if there is no parent theme found. Also the inherit behavior has been made more resilient for cases where react context fails.
-
#1322: All CSS imports within components have been removed.
- For packages: No change required! Styles will be handled manually by applications or automatically by fallback logic within iTwinUI.
-
For applications:
@itwin/itwinui-react/styles.cssshould now be manually imported at the entrypoint.If your application is still using v2, it may not be possible without npm aliases. In such a case, iTwinUI will fall back to using a dynamic import to automatically import missing CSS. However, for best experience and more robustness, we recommend that applications migrate to v3 and continue to manually import+ import '@itwin/itwinui-react/styles.css';styles.css.
-
#1302: All elements have had their class names changed to prevent conflict with older versions. These classes are considered a private implementation detail, so if you were relying on them in your code, it is strongly recommended to instead use your own classes or data attributes. Most iTwinUI components support passing a custom
classNameprop.- .iui-button { + .my-button { /* ... */ }
<Button onClick={() => {}} + className='my-button' >If you find a component where it is not possible to add a custom class, then please open an issue.
-
#1298:
Propstypes will no longer be exported for any component. UseReact.ComponentPropsorReact.ComponentPropsWithoutRefinstead. In most cases, it is also useful to manually omit theasprop because it relies on generics.import { Avatar, - type AvatarProps, } from '@itwin/itwinui-react'; + type AvatarProps = Omit<React.ComponentPropsWithoutRef<typeof Avatar>, 'as'>; -
#1433: Updated package
exportsto prevent importing internal utilities.
-
#1461: The behavior of disabled buttons has been changed to make them focusable and use
aria-disabledinstead ofdisabledattribute. While this is technically a breaking change, it shouldn't affect most uses. If you run into any issues, you can restore the old behavior using the newhtmlDisabledprop. -
#1435: SplitButton:
classNameis now passed to the button instead of the component wrapper. UsewrapperPropsif the old behavior is desired.
-
#1406: Removed
setFocusprop. Checkbox can be focused by usingautoFocusorref. -
#1371:
classNameandstylewill now always be applied on the checkbox input element (instead of conditionally being applied on the wrapper in some cases). If checkbox is used withoutlabel, then no changes should be needed. Iflabelis used, then passclassNameandstyletowrapperProps.<Checkbox label='Checkbox label' - className={wrapperClassname} - style={wrapperStyle} + wrapperProps={{ className: wrapperClassName, style: wrapperStyle }} />
-
#1406: Removed
setFocusprop. ColorPicker can be automatically focused by using it withinPopover.
-
#1406: Removed
setFocusprop. ComboBox can be focused by usinginputProps.autoFocusorinputProps.ref.
-
#1269: All dialog variants have
flexapplied by default. This means the content should be wrapped withDialog.ContentorModalContentfor optimal layout.<Modal> - my content + <ModalContent>my content</ModalContent> </Modal>
-
#1300:
modalRootIdandownerDocumentprops have been removed fromModal, in favor of the newportalprop (also available inDialog). This new prop can accept any HTMLElement, with no opinion on how it gets created.- <Modal modalRootId='my-custom-root'> + <Modal portal={{ to: myCustomRootElement }}>
-
#1565: Removed
Menucomponent in favor ofDropdownMenu.
-
#1400: The deprecated
ErrorPagecomponent will now dynamically import illustrations (previously it was statically importing the entire illustrations package, bloating the bundle). No required API changes.
-
#1406: Removed
setFocusprop. Input can be focused by usingautoFocusorref.
-
#1544:
iconDisplayStylehas been removed.svgIconis now always displayed inline and doesn't support buttons.- For icons below input, use
<StatusMessage>. For inline buttons, use<InputWithDecorations>.
- For icons below input, use
-
#1406: Removed
setFocusprop. LabeledInput can be focused by usingautoFocusorref. -
#1355: Removed
inputStyleandinputClassNameprops; style and className props are being passed down to input. AddedwrapperProps,labelProps,messageProps,messageIconProps,inputWrapperPropsto pass props to sub elements.
-
#1355:
iconDisplayStylehas been removed.svgIconis now always displayed inline and doesn't support buttons. -
#1406: Removed
setFocusprop. LabeledTextarea can be focused by usingautoFocusorref. -
#1355: Removed
textareaStyleandtextareaClassNameprops; style and className props are being passed down to textarea. AddedwrapperProps,labelProps,messageProps,messageIconPropsto pass props to sub elements.
-
#1355: Removed
selectStyleandselectClassNameprops; style and className props are being passed down to textarea. AddedwrapperProps,labelProps,messageProps,messageIconPropsto pass props to sub elements.
-
#1406: Removed
setFocusprop. Radio can be focused by usingautoFocusorref. -
#1409:
RadioTile'sclassNameandstyleprops will now always be applied on the<input>element instead of conditionally being applied on the wrapper when label is passed. AddedwrapperProps,iconProps,labelProps,subLabelPropsto individually customize each part of the component.<Radio label = 'Radio label' - className={wrapperClassname} - style={wrapperStyle} + wrapperProps={{ className: wrapperClassName, style: wrapperStyle }} />
-
#1406: Removed
setFocusprop. RadioTile can be focused by usingautoFocusorref.
-
#1406: Removed
setFocusprop. Select can be focused by usingtriggerProps.ref.
-
#1458: Top-level props (className, style, etc) now passed to the main inner div instead of to the wrapper. Use
wrapperPropsto restore old behavior.
-
#1406: Removed
setFocusprop. Slider can be focused by usingthumbProps.ref.
-
#1406: Removed
setFocusprop. Textarea can be focused by usingautoFocusorref.
-
#1527: Tile's
leftIconandrightIconprops no longer setsizefor the buttons so it must be done manually.<Tile // ... - leftIcon={<IconButton styleType='borderless'>...</IconButton>} + leftIcon={<IconButton styleType='borderless' size='small'>...</IconButton>} - rightIcon={<IconButton styleType='borderless'>...</IconButton>} + rightIcon={<IconButton styleType='borderless' size='small'>...</IconButton>} />
-
#1351:
toasterimport has been removed and replaced withuseToasterwhich returns a toaster object with the same public methods as before.- import { toaster } from '@itwin/itwinui-react'; + import { useToaster } from '@itwin/itwinui-react'; export default () => { + const toaster = useToaster(); return <button onClick={() => toaster.positive('hello')}>show</button> };
-
#1406: Removed
setFocusprop. ToggleSwitch can be focused by usingautoFocusorref.
-
#1331: Migrated Tooltip from tippy.js to floating-ui. While the basic component usage is unchanged, all advanced props that were inherited from tippy.js have been removed. New props available:
autoUpdateOptions,middlewareandportal. See new docs.- The
portalprop replaces the oldappendToprop. You can pass anHTMLElementtoportal.to. - The
referenceprop now accepts a statefulHTMLElementvalue, instead of a ref object. -
Note: Since floating-ui uses
ResizeObserver, you might need to add a mock in your tests.
- The
-
#1296: Removed previously-deprecated typography components (
Body,Headline,Leading,Small,Subheading,Title) which have been replaced byText.
-
#1514: Removed dependency on
@types/react-tableand instead exposed a package endpoint/react-tablefor allreact-tabletypes. Our types are specifically tailored to the users of our Table and thus offer better type support.import { Table } from '@itwin/itwinui-react'; - import { Column, TableState } from 'react-table'; + import { Column, TableState } from '@itwin/itwinui-react/react-table'; -
#1570: We made changes to help raise type errors that might have been previously hidden. Thus, you might have to use
satisfieswhen passing props to<Table>to make sure all your types are correct.- const data = [...] + const data = [...] satisfies MyRowDataType[]
-
#1388: Removed previously-deprecated
HorizontalTabsandVerticalTabs. Instead useTabswithorientationprop. -
#1548: Tabs are now always scrollable. The
overflowOptionsprop is now a no-op.
-
#1383: Removed previously-deprecated
UserIconandUserIconGroupcomponents (replaced withAvatarandAvatarGrouprespectively). Also removeduserIconprop fromHeader(now part ofactionsprop).
-
#1384: Removed previously-deprecated
Wizardcomponent. UseStepperfor interactive wizards, or useWorkflowDiagramfor displaying non-interactive flowcharts.
-
#1278: Adjusted calculations in ButtonGroup's
overflowButtoncallback, so that it respectsoverflowPlacementand considers the presence of the overflowButton itself.
-
#1356: ProgressRadial has been refactored to be a single
<div>instead of using a nested svg. Also it is recommended to explicitly setsizewhen using in other components. For instance,<ProgressRadial />inTable'sDefaultCell.endIconprop (example diff), or if you were previously relying on some iTwinUI component to automatically set the progress indicator to small size, you must now use<ProgressRadial size='small'>.
-
#1354: The value of the
isExpandedprop will now be used as the source of truth for all renders (i.e. "controlled" mode), rather than only for the initial render. If you were previously relying on this prop to specify the initial state, you must now maintain your own state (alongside theonToggleprop). -
#1354: The content of
ExpandableBlocknow stays in the DOM (but gets hidden) during the collapsed state. This might require adjusting your code to account for the presence of the hidden DOM element.
-
#1477: Added a new
portalContainerprop toThemeProvider. When specified, all floating elements (tooltips, toats, dialogs) under the ThemeProvider will read this prop from context and portal into it. -
#1506: Added new
Popovercomponent for public use. -
#1328: Added new
Overlaycomponent with customizable subcomponents:Overlay.Wrapper,Overlay.HiddenContent,Overlay.Overlay -
#1073: Added new
TransferListcomponent which is used to move one or more items between lists. -
#1457: Added
htmlNameprop to theHeaderButtonsubcomponent which handles the nativenameattribute in<button>. -
#1419: Added
htmlSizeprop to theInputcomponent which handles the nativesizeattribute in<input>. -
#1247: Added alternative subcomponent API to
Alert. -
#1369: Added alternative subcomponent API to
Breadcrumbs. -
#1354: Added alternative subcomponent API to
ExpandableBlock. -
#1255: Added alternative subcomponent API to
Tile. -
#1548: Added alternative subcomponent API to
Tabs. -
#1355: Added
InputGridandInputWithDecorationscomponents. -
#1355: Added
paddedprop to Icon to render icons with padding. -
#1355: Added
StatusMessagecomponent (previously used under LabeledInput, LabeledSelect, etc(. -
#1355: Added
statusprop to Input, Textarea and Select. -
#1403: Accept additional type of
JSX.Element[]andJSX.ElementformenuItemsprop inDropdownMenu.
-
#1557: Directly passing
<a>/<Button>/<span>as children is deprecated. Should be replaced withBreadcrumbs.Itemsubcomponent.
-
#1295: Deprecated
iconandbadgeprops in favor of newstartIconandendIconprops. Also affects Select and ComboBox options.
-
#1330: Deprecated
FileUploadTemplate. Should be replaced withFileUploadCard.
-
#1548: Deprecated
overflowOptionsprop inTabs. It is now a no-op, as tabs will overflow by default.