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.