In v1, UUI was a monorepo of ~84 individual npm packages (@umbraco-ui/uui-button, @umbraco-ui/uui-input, etc.). Each component had its own package.json, build config, and version.
In v2, everything is published as a single package: @umbraco-ui/uui. Components are available as individual ES module entry points for tree-shaking.
| v1 | v2 | |
|---|---|---|
| Package | 84 separate @umbraco-ui/uui-* packages |
Single @umbraco-ui/uui package |
| Install | npm install @umbraco-ui/uui-button |
npm install @umbraco-ui/uui |
| Import | import '@umbraco-ui/uui-button'; |
import '@umbraco-ui/uui/components/button/button.js'; |
| Deep import | import { UUIButtonElement } from '@umbraco-ui/uui-button/lib/uui-button.element'; |
import { UUIButtonElement } from '@umbraco-ui/uui/components/button/button.js'; |
| Bundle import | import '@umbraco-ui/uui'; |
import '@umbraco-ui/uui'; (unchanged) |
| Foundation | @umbraco-ui/uui-base |
@umbraco-ui/uui (re-exported from root) |
| CSS | @umbraco-ui/uui-css |
@umbraco-ui/uui (re-exported from root) |
| Build | Rollup per package, orchestrated by Turbo | Single Vite build |
| Lit | ^2.8.0 | ^3.0.0 |
v2 exports UUI_VERSION (the package version string) and registers itself in globalThis.__uuiVersions for multi-instance detection. See EXPORTS.md for details.
These deprecated components were removed in v2:
uui-caret— replaced byuui-symbol-expanduui-popover— replaced byuui-popover-container(native Popover API)
A jscodeshift transform is included in this repo to rewrite imports automatically. It handles component imports, foundation/CSS imports, re-exports, dynamic import() calls, and path-based references to uui-css dist/assets in config files.
# Download the transform
curl -sLO https://raw.githubusercontent.com/umbraco/Umbraco.UI/main/scripts/codemods/v2.0.0/update-imports.ts
# Dry-run (preview without writing)
npx jscodeshift -t update-imports.ts --parser tsx --extensions=ts,tsx,js,jsx --ignore-pattern='**/node_modules/**' -d ./src
# Apply changes
npx jscodeshift -t update-imports.ts --parser tsx --extensions=ts,tsx,js,jsx --ignore-pattern='**/node_modules/**' ./src
# If your project uses experimentalDecorators (TypeScript legacy decorators),
# add --parser-config to tell Babel which decorator syntax to expect:
npx jscodeshift -t update-imports.ts --parser tsx --parser-config '{"plugins":[["decorators",{"version":"legacy"}]]}' --extensions=ts,tsx,js,jsx --ignore-pattern='**/node_modules/**' ./src
# Clean up
rm update-imports.tsThe codemod only processes JS/TS files. If you reference uui-css.css in HTML files (e.g. <link> tags), update those manually:
- <link rel="stylesheet" href="./path/to/uui-css.css" />
+ <link rel="stylesheet" href="./path/to/light.css" />After running the codemod, follow the remaining manual steps below (dependency cleanup, removed components, Lit upgrade).
Remove all individual UUI packages and install the single package:
# Remove old packages
npm uninstall @umbraco-ui/uui-button @umbraco-ui/uui-input @umbraco-ui/uui-base ...
# Install v2
npm install @umbraco-ui/uuiOr if you were using the bundle package:
npm install @umbraco-ui/uui@latest- import '@umbraco-ui/uui-button';
+ import '@umbraco-ui/uui/components/button/button.js';
- import '@umbraco-ui/uui-input';
+ import '@umbraco-ui/uui/components/input/input.js';- import { UUIButtonElement } from '@umbraco-ui/uui-button/lib/uui-button.element';
+ import { UUIButtonElement } from '@umbraco-ui/uui/components/button/button.js';
- import type { UUIButtonElement } from '@umbraco-ui/uui-button/lib/uui-button.element';
+ import type { UUIButtonElement } from '@umbraco-ui/uui/components/button/button.js';- import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
+ import { defineElement } from '@umbraco-ui/uui';
- import { LabelMixin } from '@umbraco-ui/uui-base/lib/mixins';
+ import { LabelMixin } from '@umbraco-ui/uui';
- import { UUIEvent } from '@umbraco-ui/uui-base/lib/events';
+ import { UUIEvent } from '@umbraco-ui/uui';- import { UUITextStyles } from '@umbraco-ui/uui-css/lib/uui-text.styles';
+ import { UUITextStyles } from '@umbraco-ui/uui';// This still works exactly the same
import '@umbraco-ui/uui';- <link rel="stylesheet" href="node_modules/@umbraco-ui/uui-css/dist/uui-css.css" />
+ <link rel="stylesheet" href="node_modules/@umbraco-ui/uui/dist/themes/light.css" />The global Option interface (previously declared by uui-select) has been replaced with an exported UUISelectOption interface. The type shape is unchanged, so existing code will continue to work at runtime. If you reference Option as a type annotation, TypeScript will prompt you to add the import:
- const options: Array<Option> = [{ name: 'A', value: 'a' }];
+ import type { UUISelectOption } from '@umbraco-ui/uui/components/select/select.element.js';
+ const options: Array<UUISelectOption> = [{ name: 'A', value: 'a' }];The getBrightness() and getLightness() methods have been removed from UUIColorAreaElement and UUIColorPickerElement. These were HSB↔HSL conversion helpers that have been moved to shared utility functions.
If you were calling these methods on a component instance, use the standalone functions instead:
- const brightness = colorArea.getBrightness(lightness);
+ import { brightnessFromLightness } from '@umbraco-ui/uui';
+ const brightness = brightnessFromLightness(saturation, lightness);
- const lightness = colorArea.getLightness(brightness);
+ import { lightnessFromBrightness } from '@umbraco-ui/uui';
+ const lightness = lightnessFromBrightness(saturation, brightness);Note: the shared functions require an explicit saturation parameter (the old methods used this.saturation implicitly).
v1 bundled colord internally. v2 uses culori instead, which is an external dependency.
For bundler users: nothing to do — culori is listed as a dependency of @umbraco-ui/uui and is installed automatically.
For import-map / bundler-free users: add a culori entry to your import map:
{
"imports": {
"lit": "https://esm.run/lit",
+ "culori": "https://esm.run/culori",
"@umbraco-ui/uui/": "https://cdn.jsdelivr.net/npm/@umbraco-ui/uui@2/dist/"
}
}Color output format change: uui-color-picker and uui-color-area both now emit values using modern CSS space-separated syntax. The alpha channel is always included (even when fully opaque). If you were parsing the emitted value string, update your expectations:
| Component | Format | v1 output | v2 output |
|---|---|---|---|
uui-color-picker |
rgb |
rgb(255, 0, 0) |
rgb(255 0 0 / 1) |
uui-color-picker |
rgba |
rgba(255, 0, 0, 0.5) |
rgb(255 0 0 / 0.5) |
uui-color-picker |
hsl |
hsl(0, 100%, 50%) |
hsl(0 100% 50% / 1) |
uui-color-picker |
hsla |
hsla(0, 100%, 50%, 0.8) |
hsl(0 100% 50% / 0.8) |
uui-color-picker |
hex / hexa / hsv / hsva |
unchanged | unchanged |
uui-color-area |
(always rgb) | rgb(255, 0, 0) / rgba(255, 0, 0, 0.5) |
rgb(255 0 0 / 1) / rgb(255 0 0 / 0.5) |
Both old and new formats are valid CSS. Any CSS parser (or parseColor from UUI itself) will accept either.
HslaColor type: if you imported HslaColor from colord, use UUI's own export instead:
- import type { HslaColor } from 'colord';
+ import type { HslaColor } from '@umbraco-ui/uui';If you used uui-caret or uui-popover, replace them:
- <uui-caret></uui-caret>
+ <uui-symbol-expand></uui-symbol-expand>
- <uui-popover ...>
+ <uui-popover-container ...>UUI v2 requires Lit ^3.0.0. If your project uses Lit 2, follow the Lit 2 to 3 upgrade guide.
The general pattern for translating v1 imports to v2:
| v1 pattern | v2 pattern |
|---|---|
@umbraco-ui/uui-{name} |
@umbraco-ui/uui/components/{name}/{name}.js |
@umbraco-ui/uui-{name}/lib/{file} |
@umbraco-ui/uui/components/{name}/{file}.js |
@umbraco-ui/uui-base |
@umbraco-ui/uui |
@umbraco-ui/uui-base/lib/{subpath} |
@umbraco-ui/uui |
@umbraco-ui/uui-css/lib/{file} |
@umbraco-ui/uui |
v2 supports browser-native import maps for bundler-free usage.