Hi, today we are releasing version 9 of Welcome UI. This new version includes the migration to tailwindcss and the removal of xstyled and styled-components. It's a big change, but it will allow us to simplify design system and better performance.

Upgrade steps
1. Remove styled
- Remove dependencies
yarn remove @xstyled/styled-components styled-components
- Remove provider
- <WuiProvider>
- Remove styled types
Remove file styled.d.ts
1. Upgrade your dependencies and add style files
2. Script to migrate
In welcome-ui repository, run this script to change styled props to tailwind classes in your project, and apply other breaking changes from components listed below.
yarn migrate:v9 '../your_project_path'
Options for this CLI:
Usage: yarn migrate:v9 <directory> [options]Arguments:<directory> Path to the component directory to migrateOptions:--copy Create a backup copy before migration (adds -Migrated suffix)Default: Migrate files in place--interactive Enable interactive prompts to review each changeDefault: Non-interactive mode--verbose Show detailed output during migrationDefault: Show minimal output--no-format Skip final Prettier, ESLint, and Stylelint formattingDefault: Formatting enabled--no-recursive Only migrate files in target directory, not subdirectoriesDefault: Recursively scan all subdirectoriesWhat gets migrated:• External styled components: <S.Menu /> → <div className={cx("menu")} />• Inline styled components: <Box mt="sm" /> → <div className="mt-sm" />• CSS files: styles.ts → styles.module.scssExamples:# Basic migration (in place, with formatting)node index.mjs ./src/components/MyComponent# Create backup copy before migratingnode index.mjs ./src/components/MyComponent --copy# Review each change interactivelynode index.mjs ./src/components/MyComponent --interactive# Only migrate root directory filesnode index.mjs ./src/components/MyComponent --no-recursive# Combine multiple optionsnode index.mjs ./src/components/MyComponent --copy --verbose --interactive
Example of changes
-<Box backgroundColor="neutral-10" p="md" rounded="md" />+<div className="bg-neutral-10 p-md rounded-md" />
3. Fix remaining issues
We cannot cover all cases, so you may have to fix some issues manually. Check _CSS_TO_EDIT comments in your code to find them, and check the list of components changes below.
Components changes
Deprecated components
With the removed of styled-components some components are not needed anymore and have been removed:
- Box
- Flex
- Grid
- Stack
Please use div with tailwind classes instead. To help you with the migration, we provide a script to convert Box, Flex, Grid and Stack components to div with tailwind classes. See step 2 above.
Alert
To hide and icon you need now to use hideIcon prop instead of passing null to icon prop.
-<Alert icon={null} />+<Alert hideIcon />
You cannot pass a custom icon anymore.
Card
The Card.Cover component no longer accepts the shape prop.
ClearButton
the ClearButton component has been removed. You can use the CloseButton component with animatePresence prop instead.
-import { ClearButton } from '@welcome-ui/clear-button'+import { CloseButton } from '@welcome-ui/close-button'-<ClearButton />+<CloseButton animatePresence />
DropdownMenu
The DropdownMenu component no longer accepts the gutter prop. This value is set to 4px by default. If you want to remove the gutter, you can use withGutter prop.
-<DropdownMenu gutter={0} />+<DropdownMenu withGutter={false} />
Field
The Field component has been updated to improve accessibility.
The label and hint elements now have unique IDs that are linked to the input element using aria-labelledby and aria-describedby attributes. The automatic passing of props to the child input element has been removed. You can now use the useField hook to get the necessary props for your input element.
FileUpload
The FileUpload component no longer accepts the maxSize prop. If needed, you can add a custom behavior in the handleAddFile callback.
-<FileUpload maxSize={200000} />+<FileUpload handleAddFile={(file) => /* do something if file is too big */ } />
Icon
We removed the IconFont component and replaced it with a new Icon component that uses SVG icons. If you already use Icon component, you don't need to change anything (except if you use color or size props, see below).
-import { IconFont } from '@welcome-ui/icon-font'+import { NameIcon } from '@welcome-ui/icon'
We also remove color props, you can now use tailwind text class to change the color of the icon.
-<CheckIcon color="neutral-60" />+<CheckIcon className="text-neutral-60" />
Size props are only for intern values (xs, sm, ...), you can now use tailwind size class to change the size of the icon if is custom.
-<CheckIcon size="24" />+<CheckIcon className="size-(--spacing-xl)" />
alt prop has been removed, you can now use aria-label if your icon is not decorative.
-<CheckIcon alt="Check icon" />+<CheckIcon aria-label="Check icon" />
Modal
The Modal.Content component has been updated to improve its internal styling logic. The props store is no longer necessary and has been removed. The CloseButton no longer needs the props isOnHeader to adjust its styling, it's all done in CSS.
Popover
The animated prop in usePopover and usePopoverHover hooks is no longer supported. If you want to customize the animation duration, you can use hideTimeout and showTimeout props.
-const popover = usePopover({ animated: 200 })+const popover = usePopover({ hideTimeout: 200, showTimeout: 200 })
Toast
Change import for Toast:
-import { Notifications } from '@welcome-ui/toast'+import { Toast } from '@welcome-ui/toast'
To not showing icon use hideIcon property:
-<Growl icon={null} />+<Growl hideIcon />We also removed `onPauseOver` options.
New props
To display a label, use the label prop.
To hide it visually but keep it accessible for screen readers, use the hideLabel prop.
To display the label next to the input, use the inline prop.
FieldGroup
The label prop is now mandatory.
To hide it visually but keep it accessible for screen readers, use the hideLabel prop.
Utils
useScreens
To get the screens values from the theme, you need to use useScreens hook instead of useTheme.
-import { useTheme } from '@styled/styled-components'+ import { useScreens } from '@welcome-ui/utils'- const theme = useTheme()- const screens = theme.screens+ const screens = useScreens()