@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
776 lines (618 loc) • 154 kB
Markdown
---
title: 'v11'
description: 'April 21, 2026'
version: 11.8.3
generatedAt: 2026-07-29T16:51:35.601Z
checksum: 090b7d977ba4be5e2c4c04d199a30a4048416c59f443a56985df2f80629d9c40
---
# v11
This is the migration guide for @dnb/eufemia v11. It covers all breaking changes, removals, and required code updates.
> **Start here →** Follow the [Step-by-step migration procedure](#step-by-step-migration-procedure) for a structured, phase-by-phase migration workflow covering all 8 phases. The reference sections below provide details for each step.
**How to use this guide:** Start with the [Step-by-step migration procedure](#step-by-step-migration-procedure) for the ordered workflow. Reference the [per-component sections](#components) to find individual property renames for a specific component. Check [Silent failures TypeScript won't catch](#silent-failures-typescript-wont-catch) after applying changes.
> **Using AI to migrate?** Set up the [Eufemia MCP server](/uilib/usage/first-steps/tools/#ai-assistance-and-mcp-server) to give your AI agent access to the full v11 API documentation alongside this migration guide.
**Most changes fall into these categories:**
1. **snake_case → camelCase renames** — The majority of changes are mechanical property, event, and translation key renames. These can be [automated](#automated-migration-snake_case-to-camelcase).
2. **React 19 alignment** — `innerRef` → `ref`, `Context.Provider` → `Context`, and related updates.
3. **Behavioral changes and removals** — API redesigns, removed features, and changed defaults. These require manual review.
<Accordion title="Table of contents">
- [Summary of changes](#summary-of-changes)
- [v10 support timeline](#v10-support-timeline)
- [Install](#install)
- [Migration](#migration)
- [Automated migration: snake_case to camelCase](#automated-migration-snake_case-to-camelcase)
- [Migration effort levels](#migration-effort-levels)
- [Semantic renames (not just casing)](#semantic-renames-not-just-casing)
- [Import path changes](#import-path-changes)
- [Common migration mistakes](#common-migration-mistakes)
- [Cross-component prop patterns](#cross-component-prop-patterns)
- [Step-by-step migration procedure](#step-by-step-migration-procedure)
- [Find-and-replace safety guide](#find-and-replace-safety-guide)
- [Verifying your migration](#verifying-your-migration)
- [Silent failures TypeScript won't catch](#silent-failures-typescript-wont-catch)
- [Complete migration example](#complete-migration-example)
- [innerRef → ref](#innerref--ref)
- [Context.Provider → Context](#contextprovider--context)
- [Theme.Provider → Theme.Context](#themeprovider--themecontext)
- [Theme propMapping removed](#theme-propmapping-removed)
- [Theme darkMode → colorScheme](#theme-darkmode--colorscheme)
- [Components](#components)
- [labelDirection default changed to vertical](#labeldirection-default-changed-to-vertical)
- [Section](#section)
- [HelpButton](#helpbutton)
- [Autocomplete](#autocomplete)
- [Dropdown](#dropdown)
- [DrawerList](#drawerlist)
- [Anchor](#anchor)
- [Input](#input)
- [InputMasked](#inputmasked)
- [FormLabel](#formlabel)
- [Radio](#radio)
- [Textarea](#textarea)
- [Accordion](#accordion)
- [Tag](#tag)
- [Upload](#upload)
- [Stat](#stat)
- [P (paragraph)](#p)
- [Definition lists](#definition-lists)
- [Breadcrumb](#breadcrumb)
- [ProgressIndicator](#progressindicator)
- [PaymentCard](#paymentcard)
- [Divider (Horizontal Rule)](#divider-horizontal-rule)
- [Flex.Item](#flexitem)
- [Card](#card)
- [Checkbox](#checkbox)
- [Switch](#switch)
- [Logo](#logo)
- [Icon](#icon)
- [Button](#button)
- [Modal, Dialog and Drawer](#modal-dialog-and-drawer)
- [Heading](#heading)
- [H (heading elements)](#h-heading-elements)
- [Table](#table)
- [FormStatus](#formstatus)
- [Skeleton](#skeleton)
- [Tabs](#tabs)
- [Pagination](#pagination)
- [Slider](#slider)
- [Timeline](#timeline)
- [DatePicker](#datepicker)
- [NumberFormat](#numberformat)
- [StepIndicator](#stepindicator)
- [GlobalError](#globalerror)
- [ToggleButton](#togglebutton)
- [Tooltip](#tooltip)
- [GlobalStatus](#globalstatus)
- [CopyOnClick](#copyonclick)
- [Layout](#layout)
- [Helpers](#helpers)
- [Eufemia Forms](#eufemia-forms)
- [SCSS mixin renames](#scss-mixin-renames)
- [SCSS: @import → @use](#scss-import--use)
- [TypeScript](#typescript)
- [Theming](#theming)
- [Props Type Exports](#props-type-exports)
- [New in v11](#new-in-v11)
</Accordion>
## Summary of changes
- **React 19 required** — v11 requires React and React DOM v19.
- **IE and Edge (EdgeHTML) no longer supported** — All IE- and legacy-Edge-specific CSS rules have been removed from the CSS reset and component styles. Only modern evergreen browsers (Chrome, Firefox, Safari, Chromium-based Edge) are supported.
- All **snake_case** (`on_click`) events and properties have been converted to **camelCase** (`onClick`). The reason for previously using snake_case was to support Web Components – but the support was discontinued in [v10](/uilib/about-the-lib/releases/eufemia/v10-info/).
- **`labelDirection` default changed to `vertical`** — Labels render above the input by default. If you relied on horizontal labels, set `labelDirection="horizontal"` explicitly. See [labelDirection](#labeldirection-default-changed-to-vertical).
- **FormRow and FormSet removed** — Replace with Flex layout components. See [Removal of FormRow and FormSet](#removal-of-formrow-and-formset).
- **InputMasked engine replaced** — Switched from text-mask to Maskito. Custom masks using `createNumberMask` or `emailMask` must be updated. See [InputMasked](#inputmasked).
- **Logo API redesigned** — The `brand`/`variant` props are replaced with an `svg` prop import pattern. See [Logo](#logo).
- **StepIndicator redesigned** — The sidebar mode has been removed. See [StepIndicator](#stepindicator).
- **Ajv no longer auto-instantiated** — Ajv is still a dependency, but is no longer automatically instantiated. If you use JSON Schema validation, you must explicitly create and provide an Ajv instance. See [Ajv no longer auto-instantiated](#ajv-no-longer-auto-instantiated).
- **Dropdown `actionMenu`/`moreMenu` removed** — The `actionMenu` and `moreMenu` props on Dropdown have been removed. Use the new [Menu](/uilib/components/menu/) component instead.
- **NumberFormat split into variants** — The generic `<NumberFormat />` component and `format()` utility have been removed. Use variant sub-components like `<NumberFormat.Number />`, `<NumberFormat.Currency />`, etc. See [NumberFormat](#numberformat).
- **`date-fns` upgraded from v2 to v4** — If you import `date-fns` functions directly (e.g. for DatePicker's `locale` prop), update your imports to use named exports. See [DatePicker](#datepicker).
- Replaced deprecated `<Context.Provider>` with direct `<Context>` rendering across all internal context providers (React 19).
- Several exported TypeScript `interface` declarations have been converted to `type`. This prevents declaration merging but has no impact on standard usage.
- All React context value types have been renamed to use a consistent `...ContextValue` suffix (e.g. `AccordionContextProps` → `AccordionContextValue`). See [TypeScript](#typescript) for the full list.
- Event handler and render function prop types have been replaced with properly typed signatures (e.g. `(...args: any[]) => any` → `(event: AccordionChangeEvent) => void`). See [Typed event handlers](#typed-event-handlers) for the full list.
## New in v11
These components are new in v11:
- **[Menu](/uilib/components/menu/)** — A context menu component that replaces Dropdown's `actionMenu` and `moreMenu` props. Supports `Menu.Button`, `Menu.List`, `Menu.Action`, `Menu.Accordion`, `Menu.Header`, and `Menu.Divider` sub-components.
- **[List](/uilib/components/list/)** — A layout component for displaying structured lists with support for icons, titles, content, and accordion behavior.
## v10 support timeline
After the v11 release, **v10 will continue to receive critical bug fixes and security patches for 6 months**. During this period:
- **Critical bugs** and **security vulnerabilities** will be patched in v10.
- **New features** will only be added to v11.
- **Non-critical bug fixes** will only target v11.
After the 6-month window, v10 will no longer receive updates. We recommend starting your migration early to avoid last-minute pressure.
## Install
To upgrade to @dnb/eufemia v11 with NPM, use:
```bash
$ npm i @dnb/eufemia@11
# or
$ yarn add @dnb/eufemia@11
# or
$ pnpm add @dnb/eufemia@11
```
## Migration
v11 of @dnb/eufemia contains _breaking changes_.
> Important: Upgrading to v11 requires React and React DOM v19 ([React 19 Upgrade Guide](https://react.dev/blog/2024/04/25/react-19-upgrade-guide)).
### Automated migration: snake_case to camelCase
The largest category of changes in v11 is the rename of **all snake_case properties, events, and translation keys to camelCase**. This affects every component and can be automated.
**The pattern:**
- Properties: `selected_key` → `selectedKey`, `label_direction` → `labelDirection`
- Events: `on_change` → `onChange`, `on_click` → `onClick`
- Translations: `Autocomplete.no_options` → `Autocomplete.noOptions`
You can use your editor's find-and-replace to handle most of these. Since each snake_case property maps to a specific camelCase name, we recommend using the per-component lists below rather than a generic regex.
> **Note:** Some renames are not just snake_case conversions — they also change the name itself (e.g. `triangle_position` → `arrowPosition`, `opened` → `open`, `on_show` → `onOpen`). These are listed individually per component below and require manual attention.
The rest of this section covers changes that **cannot** be automated with a simple find-and-replace and need manual review.
### Migration effort levels
To help plan your migration, changes are grouped by effort:
**Automated** (find-and-replace):
- All snake_case → camelCase property, event, and translation key renames
- `innerRef` → `ref`
- `<Context.Provider>` → `<Context>`
**Semi-automated** (value renames — find-and-replace with care):
- Status value `'info'` → `'information'` (applies to `state`, `statusState`, `variant`, `confirmType`)
- Status value `'warn'` → `'warning'` (applies to `statusState`)
- `opened` → `open` on Autocomplete, Dropdown, DrawerList, DatePicker, Tooltip, Field.Date
- `on_show` → `onOpen` and `on_hide` → `onClose` on Autocomplete, Dropdown, DrawerList, DatePicker
- `prerender` → `keepInDOM` on Tabs, Accordion
- `styleType` / `style_type` → `backgroundColor` on Breadcrumb, Dialog.Body, Drawer.Body
**Manual review required:**
- InputMasked masking engine replacement (text-mask → Maskito)
- StepIndicator redesign (sidebar variant removed)
- DatePicker behavioral changes (segment elements, format strings, focus events)
- Logo API redesign (`brand`/`variant` → `svg` prop)
- Ajv no longer auto-instantiated
- FormRow and FormSet removal
- Card visual changes (outline, border-radius, default innerSpace)
- Button `variant="signal"` removal
### Semantic renames (not just casing)
These renames change the property or event name itself, not just the casing. They affect multiple components and require targeted find-and-replace:
| Old | New | Affected components |
| --------------------------------------- | -------------------------------------- | ------------------------------------------------------------------- |
| `innerRef` | `ref` | 20+ components (see [innerRef → ref](#innerref--ref)) |
| `opened` | `open` | Autocomplete, Dropdown, DrawerList, DatePicker, Tooltip, Field.Date |
| `on_show` / `on_hide` | `onOpen` / `onClose` | Autocomplete, Dropdown, DrawerList, DatePicker |
| `on_show_focus` / `on_hide_focus` | `onOpenFocus` / `onCloseFocus` | Dropdown |
| `triangle_position` | `arrowPosition` | Autocomplete, Dropdown, DrawerList |
| `styleType` / `style_type` | `backgroundColor` | Breadcrumb, Dialog.Body, Drawer.Body |
| `spacing` | `innerSpace` (object form) | Section, Dialog.Body, Drawer.Body |
| `input_class` / `textarea_class` | `inputClassName` / `textareaClassName` | Input, InputMasked, Textarea |
| `prerender` | `keepInDOM` | Tabs, Accordion |
| `as` | `element` | H (heading element) |
| `size` | `span` | Flex.Item, Card |
| `align_autocomplete` / `align_dropdown` | `align` | Autocomplete, Dropdown |
| `input_icon` | `icon` | Autocomplete |
| `clear` | `showClearButton` | Input, InputMasked |
| `visible` | `show` | ProgressIndicator |
| `show_label` | `showDefaultLabel` | ProgressIndicator |
| `active` / `forceOpen` | `open` | Tooltip |
| `position` | `placement` | Tooltip |
| `accordion` | `mode="accordion"` | Table |
| `onClosed` / `onOpened` | `onClose` / `onOpen` | Table |
| `isCollapsed` | `collapsed` | Breadcrumb |
| `expandBehaviour` | `expandBehavior` | Accordion |
| `class` | `className` | ProgressIndicator, Button, Tabs, PaymentCard |
| `contentSpacing` / `tabsSpacing` | `contentInnerSpace` / `tabsInnerSpace` | Tabs |
| `darkMode` | `colorScheme` | Theme |
### Import path changes
All import paths that changed or were removed in v11. Update these before changing component APIs — your app won't compile until these are fixed.
| Old import | New import | Notes |
| --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------- |
| `@dnb/eufemia/components/input/InputPassword` | `import { Field } from '@dnb/eufemia/extensions/forms'` then use `<Field.Password>` | Component moved to Eufemia Forms |
| `@dnb/eufemia/fragments/drawer-list/DrawerList` (`ItemContent`) | `@dnb/eufemia/fragments/drawer-list/DrawerListItem` (`ItemContent`) | Named export moved |
| `@dnb/eufemia/components/form-row/FormRowHelpers` (`includeValidProps`) | `@dnb/eufemia/shared/helpers/filterValidProps` (`pickFormElementProps`) | Function moved and renamed |
| `@dnb/eufemia/components/form-row/FormRowHelpers` (`prepareFormRowContext`) | `@dnb/eufemia/shared/helpers/filterValidProps` (`prepareFormElementContext`) | Function moved and renamed |
| `@dnb/eufemia/components/input-masked/InputMaskedHooks` | `@dnb/eufemia/components/input-masked/hooks` | Path changed |
| `@dnb/eufemia/components/input-masked/addons/createNumberMask` | **Removed** — use built-in `numberMask` prop | Addon deleted |
| `@dnb/eufemia/components/input-masked/addons/emailMask` | **Removed** — use `mask` prop directly | Addon deleted |
| `@dnb/eufemia/components/input` (`inputPropTypes`) | **Removed** | PropTypes no longer provided |
| `@dnb/eufemia/components/button` (`buttonVariantPropType`) | **Removed** | PropTypes no longer provided |
| `style/themes/theme-ui/` | `style/themes/ui/` | Path shortened |
| `style/themes/theme-sbanken/` | `style/themes/sbanken/` | Path shortened |
| `style/themes/theme-eiendom/` | `style/themes/eiendom/` | Path shortened |
| `style/themes/theme-carnegie/` | `style/themes/carnegie/` | Path shortened |
| `@dnb/eufemia/components/space/types` (`SectionSpacing`) | `@dnb/eufemia/components/space/types` (`InnerSpaceType`) | Type renamed |
| `export type { Props }` from any Field/Value/Form module | Use component-prefixed name (e.g. `FieldStringProps`) | See [Props Type Exports](#props-type-exports) |
| `@dnb/eufemia/extensions/payment-card/utils/Types` | `@dnb/eufemia/extensions/payment-card/utils/types` | Filename lowercased for consistency |
### Common migration mistakes
These changes look simple but are easy to get wrong. Pay special attention to these:
#### `spacing` → `innerSpace` requires an object, not a string
The `spacing` prop accepted a string like `"large"`. The replacement `innerSpace` requires an **object with a `block` key** to match the same vertical-only padding behavior. Using `innerSpace="large"` (plain string) applies padding on **all four sides**, which will break your layout.
**Wrong:**
```tsx
<Section innerSpace="large">Content</Section>
```
**Correct:**
```tsx
<Section innerSpace={{ block: 'large' }}>Content</Section>
```
This applies to Section, Dialog.Body, and Drawer.Body.
#### `on_show` / `on_hide` → `onOpen` / `onClose` is NOT just a casing change
The event names changed semantically. A naive snake_case→camelCase conversion would produce `onShow` / `onHide`, which are **wrong**.
| Old | Wrong (naive conversion) | Correct |
| --------------- | ------------------------ | -------------- |
| `on_show` | ~~`onShow`~~ | `onOpen` |
| `on_hide` | ~~`onHide`~~ | `onClose` |
| `on_show_focus` | ~~`onShowFocus`~~ | `onOpenFocus` |
| `on_hide_focus` | ~~`onHideFocus`~~ | `onCloseFocus` |
Affected components: Autocomplete, Dropdown, DrawerList, DatePicker. The `_focus` variants only apply to Dropdown.
Note: GlobalStatus still uses `onShow` / `onHide` — those are correct for that component and did not change semantically.
#### Component-specific props — don't apply globally
These renames only apply to specific components. Do not find-and-replace them across the entire codebase:
| Rename | Only applies to | Do NOT apply to |
| -------------------------------- | --------------------------- | -------------------------------------------- |
| `clear` → `showClearButton` | Input, InputMasked | — |
| `isCollapsed` → `collapsed` | Breadcrumb | — |
| `input_icon` → `icon` | Autocomplete | Other components that already have `icon` |
| `visible` → `show` | ProgressIndicator | Other components with `visible` prop |
| `position` → `placement` | Tooltip | Other components with `position` prop |
| `children` → `label` | Checkbox, ProgressIndicator | — |
| `as` → `element` | H (heading element) | — |
| `accordion` → `mode="accordion"` | Table | Accordion component itself |
| `size` → `span` | Flex.Item, Card | Other components where `size` is still valid |
#### `FormRow` / `FormSet` references in context providers
When replacing `FormRow`, be careful not to just rename the JSX tag. The context provider pattern also changed:
| Old | New |
| ------------------------------- | -------------- |
| `FormRow=` (in Provider config) | `formElement=` |
| `FormRow:` (in context objects) | `formElement:` |
### Cross-component prop patterns
These snake_case props appear on many components and follow the same rename pattern everywhere. Apply these as global find-and-replace within Eufemia component JSX:
| Old prop | New prop | Components that use it |
| --------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status_state` | `statusState` | Autocomplete, Checkbox, DatePicker, Dropdown, Input, InputMasked, Radio, Radio.Group, Slider, StepIndicator, Switch, Textarea, ToggleButton, ToggleButton.Group |
| `status_props` | `statusProps` | Autocomplete, Checkbox, DatePicker, Dropdown, Input, InputMasked, Radio, Radio.Group, Switch, Textarea, ToggleButton, ToggleButton.Group |
| `status_no_animation` | `statusNoAnimation` | Autocomplete, Checkbox, DatePicker, Dropdown, Input, InputMasked, Radio, Radio.Group, Switch, Textarea, ToggleButton, ToggleButton.Group |
| `label_direction` | `labelDirection` | Autocomplete, DatePicker, Dropdown, FormLabel, Input, InputMasked, ProgressIndicator, Radio.Group, Slider, Textarea, ToggleButton, ToggleButton.Group |
| `label_sr_only` | `labelSrOnly` | Autocomplete, Checkbox, DatePicker, Dropdown, Input, InputMasked, Radio.Group, Switch, Textarea, ToggleButton.Group |
| `label_position` | `labelPosition` | Checkbox, Radio, Switch |
| `icon_size` | `iconSize` | Autocomplete, Button, GlobalStatus, ProgressIndicator, ToggleButton |
| `icon_position` | `iconPosition` | Autocomplete, Button, Dropdown, ToggleButton |
| `no_animation` | `noAnimation` | Autocomplete, DatePicker, Dropdown, DrawerList, FormStatus, GlobalStatus, Modal/Dialog/Drawer, Skeleton, StepIndicator |
| `on_change` | `onChange` | Nearly all interactive components |
| `on_focus` | `onFocus` | Autocomplete, Input, Textarea |
| `on_blur` | `onBlur` | Autocomplete, Input, Textarea |
| `on_click` | `onClick` | Button, StepIndicator, Tabs, Table.ClickableHead |
| `inner_ref` | `ref` | All components that accepted `innerRef` (see [innerRef → ref](#innerref--ref) for the full list) |
**Status value renames** — apply to all components that accept `statusState` or `state`:
| Old value | New value |
| --------- | --------------- |
| `'warn'` | `'warning'` |
| `'info'` | `'information'` |
**CSS class renames** — apply wherever these CSS classes are referenced:
| Old CSS class | New CSS class |
| ---------------------------------------- | ------------------------------------------ |
| `dnb-autocomplete--opened` | `dnb-autocomplete--open` |
| `dnb-dropdown--opened` | `dnb-dropdown--open` |
| `dnb-drawer-list--opened` | `dnb-drawer-list--open` |
| `dnb-date-picker--opened` | `dnb-date-picker--open` |
| `dnb-progress-indicator--visible` | `dnb-progress-indicator--show` |
| `dnb-anchor--contrast` | `dnb-anchor--surface-dark` |
| `dnb-number-format--selectall` | `dnb-number-format--select-all` |
| `dnb-autocomplete__suffixValue` | `dnb-autocomplete__suffix-value` |
| `dnb-height-animation__compensateForGap` | `dnb-height-animation__compensate-for-gap` |
### Step-by-step migration procedure
Follow these steps **in order**. Steps in Phase 1 are safe to apply as global find-and-replace across your entire codebase. Steps in later phases require scoping or manual review.
#### Phase 1: Global find-and-replace (safe across entire codebase)
These renames only exist as Eufemia prop/event names and won't collide with other libraries:
1. Replace all **snake_case props and events** with their camelCase equivalents. Use the per-component lists in the [Components](#components) section below. The most common ones: `on_change` → `onChange`, `on_click` → `onClick`, `status_state` → `statusState`, `label_direction` → `labelDirection`, `label_sr_only` → `labelSrOnly`, `no_animation` → `noAnimation`, `icon_size` → `iconSize`, `icon_position` → `iconPosition`.
2. Replace `innerRef` with `ref` on all Eufemia components.
3. Replace `<Context.Provider>` with `<Context>` when using Eufemia contexts directly.
4. Replace the status value `'info'` with `'information'` (applies to `state`, `statusState`, `variant`, `confirmType`).
5. Replace the status value `'warn'` with `'warning'` (applies to `statusState`).
6. Replace `input_class` (or `inputClass`) with `inputClassName` on Input and InputMasked.
7. Replace `textarea_class` (or `textareaClass`) with `textareaClassName` on Textarea.
#### Phase 2: Targeted find-and-replace (scope to specific components)
These renames use generic names that exist in non-Eufemia code. Scope your find-and-replace to JSX using the affected component:
8. Replace `opened` with `open` — **only on** Autocomplete, Dropdown, DrawerList, DatePicker, Tooltip, Field.Date.
9. Replace `on_show` with `onOpen` and `on_hide` with `onClose` — **only on** Autocomplete, Dropdown, DrawerList, DatePicker. _(Not just a casing change — the name changed semantically. GlobalStatus still uses `onShow`/`onHide`.)_
10. Replace `triangle_position` with `arrowPosition` — **only on** Autocomplete, Dropdown, DrawerList.
11. Replace `clear` with `showClearButton` — **only on** Input, InputMasked.
12. Replace `isCollapsed` with `collapsed` — **only on** Breadcrumb.
13. Replace `visible` with `show` — **only on** ProgressIndicator.
14. Replace `position` with `placement` — **only on** Tooltip.
15. Replace `children` with `label` — **only on** Checkbox, ProgressIndicator.
16. Replace `active` or `forceOpen` with `open` — **only on** Tooltip.
17. Replace `as` with `element` — **only on** H (heading element).
18. Replace `size` with `span` — **only on** Flex.Item, Card.
19. Replace `input_icon` with `icon` — **only on** Autocomplete.
20. Replace `accordion` with `mode="accordion"` — **only on** Table.
21. Replace `prerender` with `keepInDOM` — **only on** Tabs, Accordion.
22. Replace `styleType` (or `style_type`) with `backgroundColor` — **only on** Breadcrumb, Dialog.Body, Drawer.Body.
23. Replace `contentSpacing` with `contentInnerSpace` and `tabsSpacing` with `tabsInnerSpace` — **only on** Tabs.
#### Phase 3: Structural and visual changes (require code modification or review)
24. **Visual review:** The `labelDirection` default has changed to `vertical`. If your layouts relied on horizontal labels, add `labelDirection="horizontal"` explicitly. See [labelDirection default changed to vertical](#labeldirection-default-changed-to-vertical).
25. **Visual review:** Card outline, border-radius, and default `innerSpace` have changed. Review your Card layouts. See [Card](#card).
26. Replace `spacing` with `innerSpace={{ block: 'value' }}` on Section, Dialog.Body, Drawer.Body. Do NOT use `innerSpace="large"` — it must be an object. See [Section](#section).
27. Replace `Theme.Provider` with `Theme.Context` and `darkBackground` with `surface="dark"`. See [Theme.Provider → Theme.Context](#themeprovider--themecontext).
28. Replace `<FormRow>` with `<Flex.Horizontal align="baseline">` and `<FormRow vertical>` with `<Flex.Vertical>`. Replace `FormRow=` with `formElement=` in Provider config. See [Removal of FormRow and FormSet](#removal-of-formrow-and-formset).
29. Replace `openState="opened"` with `open={true}` and `openState="closed"` with `open={false}` on Modal/Dialog/Drawer.
30. Update `dateFormat` and `returnFormat` strings: `YYYY` → `yyyy`, `DD` → `dd` on DatePicker.
31. Replace `Stat.Amount` with `Stat.Number`, `Stat.Info variant="default"` with `variant="plain"`.
32. Replace Logo `brand`/`variant` props with `svg` prop import pattern. See [Logo](#logo).
#### Phase 4: Import path and module changes
33. Update all changed import paths. See [Import path changes](#import-path-changes).
34. If using Ajv with JSON Schema validation, add `ajvInstance={makeAjvInstance()}` to `Form.Handler`. See [Ajv no longer auto-instantiated](#ajv-no-longer-auto-instantiated).
35. Replace `InputPassword` import with `Field.Password` from Eufemia Forms. See [InputPassword moved to Field.Password](#inputpassword-moved-to-fieldpassword).
36. Replace `StepsLayout` with `Wizard.Container`, `StepsLayout.Step` with `Wizard.Step`, etc.
#### Phase 5: SCSS changes
37. If you import Eufemia SCSS source files with `@import`, replace with `@use` and namespace your calls. See [SCSS: @import → @use](#scss-import--use).
38. Rename all SCSS mixin references to camelCase. See [SCSS mixin renames](#scss-mixin-renames).
39. Remove `extendFocusRing` and `componentReset` SCSS mixin calls — they have been deleted.
#### Phase 6: TypeScript type updates
40. Update any imported context value types (`AccordionContextProps` → `AccordionContextValue`, etc.). See [TypeScript](#typescript).
41. Update any Props type imports (`Props` → component-prefixed name). See [Props Type Exports](#props-type-exports).
42. Update event handler types to match new typed signatures. See [Typed event handlers](#typed-event-handlers).
#### Phase 7: Eufemia Forms behavioral changes
43. Replace `validator` with `onChangeValidator` on all Field components.
44. Replace `continuousValidation` with `validateContinuously` on all Field components.
45. Update `errorMessages` object keys: `required` → `Field.errorRequired`, `pattern` → `Field.errorPattern`, etc. See [Error handling](#error-handling).
46. Replace `Form.useError` with `Form.useValidation`, `Form.useLocale` with `Form.useTranslation`.
47. Replace `Form.Visibility` props: `withValue` → `hasValue`, `pathValue`/`whenValue` → `visibleWhen`.
48. Replace `Form.FieldProps` with `Field.Provider`.
49. Replace `<Card stack>` with `<Form.Card>` and `<Card>` (inside forms) with `<Form.Card>`.
50. Replace `Iterate.ArrayPushButton` with `Iterate.PushButton` and `Iterate.ArrayRemoveElementButton` with `Iterate.RemoveButton`.
51. Replace `requireCommit` with `preventUncommittedChanges` on `Iterate.PushContainer`.
52. Replace `active` with `include` and `activeWhen` with `includeWhen` on `Wizard.Step`.
53. Replace Form.Iterate label variable `{itemNr}` with `{itemNo}`.
54. Review all remaining changes in the [Eufemia Forms](#eufemia-forms) section.
#### Phase 8: Verify
55. Run `npx tsc --noEmit` to catch remaining type errors.
56. Run your tests. Update any test selectors that query DatePicker/Expiry `input` elements (now `role="spinbutton"` sections).
57. Search for remaining snake_case patterns using the grep command in [Verifying your migration](#verifying-your-migration).
### Find-and-replace safety guide
**Safe for global find-and-replace** — these prop names are Eufemia-specific and won't collide with other code:
`on_change`, `on_click`, `on_focus`, `on_blur`, `on_submit`, `on_key_down`, `on_type`, `on_select`, `on_clear`, `on_open`, `on_close`, `on_cancel`, `on_reset`, `on_complete`, `on_resize`, `on_end`, `on_load`, `on_startup`, `on_adjust`, `on_days_render`, `on_submit_focus`, `on_submit_blur`, `status_state`, `status_props`, `status_no_animation`, `label_direction`, `label_sr_only`, `label_position`, `icon_size`, `icon_position`, `no_animation`, `inner_ref`, `selected_key`, `default_value`, `prevent_selection`, `prevent_close`, `keep_open`, `independent_width`, `fixed_position`, `enable_body_lock`, `skip_portal`, `cache_hash`, `no_scroll_animation`, `min_height`, `max_height`, `input_element`, `submit_element`, `submit_button_title`, `submit_button_icon`, `submit_button_variant`, `clear_button_title`, `keep_placeholder`, `input_attributes`, `inner_element`.
> **Note:** `on_state_update` is **not** in this list because it has been removed, not renamed. If you used `on_state_update`, replace it with `onChange` instead.
**Must be scoped to specific components** — these names exist outside Eufemia or overlap across components with different meanings:
| Rename | Scope to | Risk if applied globally |
| -------------------------------- | ------------------------------------------------------------------- | ---------------------------------------------------- |
| `opened` → `open` | Autocomplete, Dropdown, DrawerList, DatePicker, Tooltip, Field.Date | Collides with HTML `open` attribute on `<details>` |
| `clear` → `showClearButton` | Input, InputMasked | Collides with generic `clear` functions |
| `visible` → `show` | ProgressIndicator | Collides with generic `visible` props |
| `position` → `placement` | Tooltip | Collides with CSS `position` prop/style |
| `children` → `label` | Checkbox, ProgressIndicator | `children` is a React universal prop |
| `as` → `element` | H (heading element) | `as` is used by styled-components and other libs |
| `size` → `span` | Flex.Item, Card | `size` is used by many non-Eufemia components |
| `active` → `open` | Tooltip | `active` is a common generic prop |
| `accordion` → `mode="accordion"` | Table | Prop-to-prop+value change, not a simple rename |
| `input_icon` → `icon` | Autocomplete | Other components already have different `icon` props |
| `spacing` → `innerSpace` | Section, Dialog.Body, Drawer.Body | Requires object form `{ block: '...' }`, not string |
| `on_show` → `onOpen` | Autocomplete, Dropdown, DrawerList, DatePicker | Semantic change; GlobalStatus keeps `onShow` |
| `on_hide` → `onClose` | Autocomplete, Dropdown, DrawerList, DatePicker | Semantic change; GlobalStatus keeps `onHide` |
### Verifying your migration
After applying changes, use these commands to validate:
**TypeScript check** — catches missed renames, wrong prop types, and removed APIs:
```bash
npx tsc --noEmit
```
**Search for remaining snake_case** — catches props you missed:
```bash
grep -rn 'on_\|status_\|label_\|icon_\|_class\b\|inner_ref\|_state\|_position\|_button\|_text\|_sr_' \
--include='*.tsx' --include='*.ts' src/
```
> **Note:** This grep only catches snake_case patterns. Semantic renames like `opened` → `open`, `prerender` → `keepInDOM`, `clear` → `showClearButton`, and `expandBehaviour` → `expandBehavior` require manual review using the [Semantic renames](#semantic-renames-not-just-casing) table.
**Common TypeScript errors and what they mean:**
| Error | Cause | Fix |
| ----------------------------------------------------------------- | ------------------------------------ | --------------------------------------------------------- |
| `Property 'on_change' does not exist` | Missed snake_case → camelCase rename | Replace with `onChange` |
| `Property 'innerRef' does not exist` | Missed innerRef → ref | Replace with `ref` |
| `Type '"info"' is not assignable` | Missed status value rename | Replace `'info'` with `'information'` |
| `Type '"warn"' is not assignable` | Missed status value rename | Replace `'warn'` with `'warning'` |
| `Module not found: '@dnb/eufemia/components/input/InputPassword'` | Import path moved | Use `Field.Password` from `@dnb/eufemia/extensions/forms` |
| `Property 'spacing' does not exist` | Removed prop | Replace with `innerSpace={{ block: 'value' }}` |
| `Property 'brand' does not exist` on Logo | Logo API redesigned | Import SVG component and use `svg` prop |
| `Type '"signal"' is not assignable` on Button | Variant removed | Use `variant="primary"` or `variant="secondary"` |
| `Cannot find name 'FormRow'` | Component removed | Replace with `Flex.Horizontal` or `Flex.Vertical` |
| `Property 'opened' does not exist` | Prop renamed | Replace with `open` |
### Silent failures TypeScript won't catch
TypeScript catches most v10 → v11 errors, but these three categories **compile without errors and fail silently at runtime**. You must search for them manually after migration.
#### 1. Data object property renames
Dropdown, Autocomplete, DrawerList, and Field.Selection accept `data` arrays with objects. The `DrawerListDataArrayObject` type allows arbitrary keys (`[key: string]: any`), so TypeScript **will not flag** old snake_case property names. The component simply won't find the values it expects.
**Compiles but broken:**
```tsx
<Dropdown
data={[
{ selected_key: 'no', content: 'Norway' }, // silent failure
{ selected_key: 'se', content: 'Sweden' }, // silent failure
]}
/>
```
**Correct:**
```tsx
<Dropdown
data={[
{ selectedKey: 'no', content: 'Norway' },
{ selectedKey: 'se', content: 'Sweden' },
]}
/>
```
Search for old data property names:
```bash
grep -rn 'selected_key\|selected_value\|suffix_value\|search_content\|class_name' \
--include='*.tsx' --include='*.ts' src/
```
#### 2. Event callback return object renames
Several components renamed properties on the objects passed to event callbacks. If you destructure the old property names, the values will be `undefined` at runtime with no TypeScript error (because callback parameter types are often inferred loosely).
**DatePicker `onChange` return object:**
| Old property | New property |
| --------------------- | ------------------ |
| `days_between` | `daysBetween` |
| `is_valid` | `isValid` |
| `is_valid_start_date` | `isValidStartDate` |
| `is_valid_end_date` | `isValidEndDate` |
**Field.Date `onType` return object:**
| Old property | New property |
| ------------ | ------------ |
| `start_date` | `startDate` |
| `end_date` | `endDate` |
| `is_valid` | `isValid` |
Search for old callback property access:
```bash
grep -rn 'days_between\|is_valid\|is_valid_start_date\|is_valid_end_date\|start_date\|end_date' \
--include='*.tsx' --include='*.ts' src/
```
#### 3. CSS class selectors in strings and tests
CSS class names used in `querySelector`, test assertions, or CSS/SCSS files are plain strings that TypeScript cannot validate.
Search for all renamed CSS classes:
```bash
grep -rn 'dnb-autocomplete--opened\|dnb-dropdown--opened\|dnb-drawer-list--opened\|dnb-date-picker--opened\|dnb-progress-indicator--visible\|dnb-anchor--contrast\|dnb-number-format--selectall\|dnb-section--spacing' \
--include='*.tsx' --include='*.ts' --include='*.scss' --include='*.css' src/
```
Also check DatePicker/Expiry test selectors — the visible date segments changed from native `input` elements to `role="spinbutton"` sections:
```tsx
// Before (v10) — queried native input elements
document.querySelector('.dnb-date-picker input')
// After (v11) — use role-based selectors
document.querySelector('[role="spinbutton"]')
// or
document.querySelector('.dnb-segmented-field__section')
```
#### 4. Theme `darkMode` prop silently ignored
The `darkMode` prop on `Theme` was replaced with `colorScheme`. Passing `darkMode` compiles without error but is silently ignored. The CSS class also changed from `eufemia-theme__dark-mode` to `eufemia-theme__color-scheme--dark`.
Search for old usage:
```bash
grep -rn 'darkMode\|eufemia-theme__dark-mode' \
--include='*.tsx' --include='*.ts' --include='*.scss' --include='*.css' src/
```
#### 5. Provider `locales` prop silently ignored
The `locales` prop on `Provider` and `Context` was removed in favor of `translations`. Passing `locales` compiles without error but is silently ignored, meaning your custom translations will not be applied.
Search for old usage:
```bash
grep -rn 'locales=' --include='*.tsx' --include='*.ts' src/
```
### Complete migration example
This example shows a realistic v10 component migrated to v11, combining multiple change categories:
**Before (v10):**
```tsx
import {
Input,
Dropdown,
DatePicker,
Section,
Button,
FormRow,
} from '@dnb/eufemia'
import { Provider } from '@dnb/eufemia/shared'
function MyForm({ formRef }) {
return (
<Provider FormRow={{ label_direction: 'vertical' }}>
<Section spacing="large" style_type="white">
<FormRow>
<Input
label="Name"
on_change={({ value }) => console.log(value)}
status="Error message"
status_state="error"
innerRef={formRef}
/>
<Dropdown
label="Country"
selected_key="no"
on_change={({ data }) => console.log(data)}
opened={false}
on_show={() => console.log('opened')}
on_hide={() => console.log('closed')}
triangle_position="left"
data={[
{ selected_key: 'no', content: 'Norway' },
{ selected_key: 'se', content: 'Sweden' },
]}
/>
<DatePicker
label="Start date"
date_format="YYYY/MM/DD"
return_format="YYYY-MM-DD"
on_change={({ date }) => console.log(date)}
on_show={() => console.log('shown')}
on_hide={() => console.log('hidden')}
/>
</FormRow>
<Button variant="signal" on_click={() => console.log('submit')}>
Submit
</Button>
</Section>
</Provider>
)
}
```
**After (v11):**
```tsx
import {
Input,
Dropdown,
Flex,
DatePicker,
Section,
Button,
} from '@dnb/eufemia'
import { Provider } from '@dnb/eufemia/shared'
function MyForm({ formRef }) {
return (
<Provider formElement={{ labelDirection: 'vertical' }}>
<Section innerSpace={{ block: 'large' }} backgroundColor="white">
<Flex.Horizontal align="baseline">
<Input
label="Name"
onChange={({ value }) => console.log(value)}
status="Error message"
statusState="error"
ref={formRef}
/>
<Dropdown
label="Country"
selectedKey="no"
onChange={({ data }) => console.log(data)}
open={false}
onOpen={() => console.log('opened')}
onClose={() => console.log('closed')}
arrowPosition="left"
data={[
{ selectedKey: 'no', content: 'Norway' },
{ selectedKey: 'se', content: 'Sweden' },
]}
/>
<DatePicker
label="Start date"
dateFormat="yyyy/MM/dd"
returnFormat="yyyy-MM-dd"
onChange={({ date }) => console.log(date)}
onOpen={() => console.log('shown')}
onClose={() => console.log('hidden')}
/>
</Flex.Horizontal>
<Button variant="primary" onClick={() => console.log('submit')}>
Submit
</Button>
</Section>
</Provider>
)
}
```
**What changed (13 categories in one component):**
1. `FormRow` → `Flex.Horizontal align="baseline"` (removed component)
2. `FormRow={{ label_direction: 'vertical' }}` → `formElement={{ labelDirection: 'vertical' }}` (Provider config)
3. `spacing="large"` → `innerSpace={{ block: 'large' }}` (structural change — object required)
4. `style_type="white"` → `backgroundColor="white"` (semantic rename)
5. `on_change` / `on_click` → `onChange` / `onClick` (snake_case → camelCase)
6. `status_state` → `statusState` (snake_case → camelCase)
7. `innerRef` → `ref` (React 19)
8. `selected_key` → `selectedKey` (snake_case → camelCase, in both props and data objects)
9. `opened` → `open` (semantic rename)
10. `on_show` / `on_hide` → `onOpen` / `onClose` (semantic rename — NOT `onShow`/`onHide`)
11. `triangle_position` → `arrowPosition` (semantic rename)
12. `date_format="YYYY/MM/DD"` → `dateFormat="yyyy/MM/dd"` (casing + format string change)
13. `variant="signal"` → `variant="primary"` (removed variant)
### innerRef → ref
React 19 passes `ref` as a regular prop, making `forwardRef` and custom `innerRef` patterns unnecessary. All Eufemia components that previously accepted an `innerRef` prop now accept `ref` directly.
**Before:**
```tsx
<Input innerRef={myRef} />
<Button innerRef={myRef} />
<Element innerRef={myRef} />
```
**After:**
```tsx
<Input ref={myRef} />
<Button ref={myRef} />
<Element ref={myRef} />
```
Affected c