Migration Guide
Migrating to 1.2.3 (from 1.2.2)
ScrollContainer no longer fills its parent by default
Previously, ScrollContainer always applied flexGrow: 1 internally, even without a flex prop — this was undocumented and invisible on a normal full-screen scroll view, but caused unrelated bugs (e.g. Popup expanding to fill the whole screen when it contained a ScrollContainer). ScrollContainer now only grows when flex is explicitly passed.
If you have a ScrollContainer that relies on filling the remaining space of its parent (the common "main scroll area of a screen" pattern) and it doesn't already pass flex, add flex={1}:
// Before
<Container flex={1}>
<ScrollContainer padding={16}>
{/* was implicitly filling the screen */}
</ScrollContainer>
</Container>
// After
<Container flex={1}>
<ScrollContainer flex={1} padding={16}>
{/* now explicit */}
</ScrollContainer>
</Container>
If you were relying on ScrollContainer sizing to its content (e.g. nested inside Popup), no change is needed — that's now the default.
Migrating to 1.2.2 (from 1.2.1)
Popup's type prop removed
Presentation is now automatic and platform-based: Popup always renders as a bottom sheet on native and always as a centered dialog on web. Remove any type prop passed to Popup. Message, which is built on Popup, loses its type prop for the same reason.
// Before
<Popup type="sheet" title="Select Option" renderToggleButton={...}>
...
</Popup>
// After
<Popup title="Select Option" renderToggleButton={...}>
...
</Popup>
If you need to know which presentation is active (e.g. to conditionally apply bottom safe-area insets), read the resolved value from usePopup().type (or the usePopup().isDialog shorthand) instead — it just can no longer be set.
New required peer dependency: @swmansion/react-native-bottom-sheet
Popup now renders as a native bottom sheet using @swmansion/react-native-bottom-sheet on native platforms. Install it alongside your other peer dependencies:
npx expo install @swmansion/react-native-bottom-sheet
No other setup is required — MultinaireUI wraps its children in the necessary provider automatically.
Migrating to 1.0.7 (from 1.0.6)
Package renamed: @multinaire/ui → @multinaire/expo-ui
This is a breaking change release. Update the dependency and every import:
# Remove old package
npm uninstall @multinaire/ui
# Install new package
npm install @multinaire/expo-ui
// Before
import MultinaireUI, { Button, Typography } from '@multinaire/ui';
// After
import MultinaireUI, { Button, Typography } from '@multinaire/expo-ui';
Also update:
-
Any
TranslationSchemaaugmentation:// Beforedeclare module '@multinaire/ui' { ... }// Afterdeclare module '@multinaire/expo-ui' { ... } -
tsconfig.jsonpath mappings, if you use the example app pattern:// Before"paths": {"@multinaire/ui": ["../build/index"]}// After"paths": {"@multinaire/expo-ui": ["../build/index"]}
Expo SDK 56 required
The library now targets Expo SDK 56. Upgrade your app before updating:
npx expo install expo@^56.0.0 react-native react-native-reanimated react-native-worklets react-native-screens react-native-svg
See the Expo SDK 56 upgrade guide if you're coming from SDK 55 or earlier.
@react-navigation/native no longer required
If you installed @react-navigation/native solely to satisfy this package's peer dependencies, you can remove it — navigation types are now sourced through expo-router:
npm uninstall @react-navigation/native
No code changes are required; this only affects your package.json.
Migrating to 1.0.4 (from 1.0.3)
AnimatedTouchableOpacity renamed to AnimatedPressable
All interactive components moved from TouchableOpacity to Pressable to enable hover support on web/desktop. The exported AnimatedTouchableOpacity component was renamed accordingly. If you imported it directly, update the name:
// Before
import { AnimatedTouchableOpacity } from '@multinaire/ui';
<AnimatedTouchableOpacity activeOpacity={0.8} onPress={onPress} />;
// After
import { AnimatedPressable } from '@multinaire/ui';
<AnimatedPressable onPress={onPress} />;
AnimatedPressable is an Animated-wrapped Pressable, so the activeOpacity prop no longer applies. For the same hover/press opacity feedback the built-in components use, combine it with the new usePressableInteraction hook:
import { AnimatedPressable, usePressableInteraction } from '@multinaire/ui';
function MyButton({ onPress }) {
const { animatedStyle, overrideProps } = usePressableInteraction();
return (
<AnimatedPressable style={animatedStyle} onPress={onPress} {...overrideProps} />
);
}
Migrating to 1.0.3 (from 1.0.2)
useScreenOptions — deprecated properties removed
The stack, stackWithOverrides, topTab, topTabWithOverrides, bottomTab, bottomTabWithOverrides, sideBar, and sideBarWithOverrides properties have been removed. If you haven't already migrated away from them, update your navigators now:
// Before (removed)
const { stack, bottomTab, topTabWithOverrides } = useScreenOptions();
<Stack screenOptions={stack} />
<Tabs screenOptions={bottomTab} />
<Tabs screenOptions={topTabWithOverrides({ lazy: false })} />
// After
const { screenOptions } = useScreenOptions('stack');
const { screenOptions: tabOptions } = useScreenOptions('bottom-tab');
const { screenOptions: topOptions } = useScreenOptions('top-tab');
<Stack screenOptions={screenOptions()} />
<Tabs screenOptions={tabOptions()} />
<Tabs screenOptions={topOptions({ lazy: false })} />
Localization — 'system' renamed to 'auto'
The 'system' value for defaultLanguage has been replaced with 'auto'. If you passed defaultLanguage="system" explicitly, rename it:
// Before
<MultinaireUI defaultLanguage="system" translations={...}>
// After
<MultinaireUI defaultLanguage="auto" translations={...}>
'auto' is still the default, so no change is needed if you relied on the default behaviour.
The language and changeLanguage types in LocalizationContext and useLocalization no longer include 'system'. The languages array returned by useLocalization now contains only concrete locale codes — remove any 'system' entry handling in language pickers:
// Before — filtering out 'system' before rendering
const { languages } = useLocalization();
const displayLanguages = languages.filter(l => l !== 'system');
// After — languages only contains locale codes, no filtering needed
const { languages } = useLocalization();
Migrating to 1.0.2 (from 1.0.1)
Toggle default color
The color prop default changed from 'primary' to 'success'. If you relied on the old default, pass color="primary" explicitly:
// Before (implicit primary)
<Toggle value={isEnabled} onChange={setIsEnabled} />
// After — add color prop to keep the old appearance
<Toggle value={isEnabled} color="primary" onChange={setIsEnabled} />
useScreenOptions — new API
useScreenOptions now accepts a navigator type and returns a screenOptions function together with title(), tabBarLabel(), and tabBarIcon() helpers. The old property-based API still works but is deprecated and will be removed in a future minor version.
// Before (deprecated)
const { stack, topTab, bottomTabWithOverrides } = useScreenOptions();
<Stack screenOptions={stack} />
<Tabs screenOptions={topTab} />
<Tabs screenOptions={bottomTabWithOverrides({ tabBarActiveTintColor: 'red' })} />
// After
const { screenOptions } = useScreenOptions('stack');
const { screenOptions: tabOptions } = useScreenOptions('top-tab');
const { screenOptions: bottomOptions } = useScreenOptions('bottom-tab');
<Stack screenOptions={screenOptions()} />
<Tabs screenOptions={tabOptions()} />
<Tabs screenOptions={bottomOptions({ tabBarActiveTintColor: 'red' })} />
The title(), tabBarLabel(), and tabBarIcon() helpers make screen options fully type-safe when TranslationSchema is augmented:
const { screenOptions, title, tabBarIcon } = useScreenOptions('bottom-tab');
<Tabs.Screen
name="home"
options={{
...screenOptions(),
title: title('home'), // type-checked against TranslationSchema
tabBarIcon: tabBarIcon('Home'),
}}
/>
createTabSceenOptions renamed
The internal export createTabSceenOptions (typo) has been renamed to createTabScreenOptions. Update any direct imports:
// Before
import { createTabSceenOptions } from '@multinaire/ui';
// After
import { createTabScreenOptions } from '@multinaire/ui';
Type-safe i18n with TranslationSchema (opt-in)
String props across all components now accept TranslationKey. To unlock compile-time key checking, augment the TranslationSchema interface once in your project:
// i18n.d.ts (in your app root)
import en from '@/assets/translations/en.json';
import fr from '@/assets/translations/fr.json';
declare module '@multinaire/ui' {
interface TranslationSchema {
en: typeof en;
fr: typeof fr;
}
}
After this, passing an unknown string to any component title, placeholder, or errorText prop will produce a TypeScript error. This is entirely opt-in — without the augmentation all string props accept string as before.
Container — safeAreaEdges + onPress are mutually exclusive
Combining both props now throws a runtime error. Wrap the SafeAreaView in a separate pressable instead:
// Before (silently broken layout)
<Container safeAreaEdges={['top']} onPress={handlePress}>
{children}
</Container>
// After
<Container safeAreaEdges={['top']}>
<Container onPress={handlePress}>
{children}
</Container>
</Container>
Migrating to 1.0.1 (from 1.0.0)
useUI → useTheme
The hook was shipped under the wrong name in 1.0.0. Replace every usage:
// Before
const { colors, variables, fonts } = useUI();
// After
const { colors, variables, fonts } = useTheme();
Migrating to 1.0.0 (from 0.3.x)
This is a breaking change release. The package has been renamed and all Multinaire prefixes have been stripped from the public API.
1. Update the package name
# Remove old package
npm uninstall @multinaire/multinaire-design
# Install new package
npm install @multinaire/ui
2. Update all imports
Replace every import from @multinaire/multinaire-design with @multinaire/ui:
// Before
import MultinaireDesignProvider, {
useMultinaireTheme,
useMultinaireLocalization,
MultinaireButton,
MultinaireText,
} from '@multinaire/multinaire-design';
// After
import MultinaireUI, {
useTheme,
useLocalization,
Button,
Typography,
} from '@multinaire/ui';
3. Rename every symbol
Use the tables below as a find-and-replace reference.
Root provider
| Before | After |
|---|---|
MultinaireDesignProvider | MultinaireUI |
MultinaireDesignProps | MultinaireUIProps |
Hooks
| Before | After |
|---|---|
useMultinaireTheme | useTheme |
useMultinaireThemeMode | useThemeMode |
useMultinaireLocalization | useLocalization |
useMultinaireModal | usePopup |
useMultinaireKeyboard | useKeyboard |
useMultinaireResponsiveDesign | useResponsiveDesign |
useMultinaireLoadingAnimation | useAnimate |
Icons
| Before | After |
|---|---|
MultinaireIcons | Icons |
Components with intent-based renames
| Before | After |
|---|---|
MultinaireText | Typography |
MultinaireImage | Photo |
MultinaireLoading | Animate |
MultinaireScrollView | ScrollContainer |
MultinaireSwitch | Toggle |
MultinaireModal | Popup |
MultinaireModalHeader | PopupHeader |
MultinaireModalToggleButton | PopupToggleButton |
MultinaireKeyboardAvoidingView | KeyboardAvoidingContainer |
MultinaireListView | ListContainer |
MultinairePageView | PageContainer |
MultinaireTabView | TabContainer |
Components — prefix-only strip
| Before | After |
|---|---|
MultinaireContainer | Container |
MultinaireCard | Card |
MultinaireBadge | Badge |
MultinaireDivider | Divider |
MultinaireGap | Gap |
MultinaireIcon | Icon |
MultinairePositioned | Positioned |
MultinaireAvatar | Avatar |
MultinaireMessage | Message |
MultinaireButton | Button |
MultinaireIconButton | IconButton |
MultinaireActionButton | ActionButton |
MultinaireMenuButton | MenuButton |
MultinaireSocialLoginButton | SocialLoginButton |
MultinaireFloatingActionButton | FloatingActionButton |
MultinaireInput | Input |
MultinairePickerButton | PickerButton |
MultinaireMediaPickerButton | MediaPickerButton |
MultinaireCheckbox | Checkbox |
MultinairePagination | Pagination |
MultinairePage | Page |
MultinaireTopTab | TopTab |
MultinaireBottomTab | BottomTab |
MultinaireListPicker | ListPicker |
MultinaireListPickerItem | ListPickerItem |
MultinaireDateTimePicker | DateTimePicker |
MultinaireDialog | Dialog |
MultinaireMenu | Menu |
MultinaireStackHeader | StackHeader |
MultinaireTabBar | TabBar |
MultinaireTabHeader | TabHeader |
MultinaireSideBar | SideBar |
Prop types — drop the Multinaire prefix and are renamed to match their component names exactly:
| Old | New |
|---|---|
TextProps | TypographyProps |
ImageProps | PhotoProps |
SwitchProps | ToggleProps |
KeyboardAvoidingViewProps | KeyboardAvoidingContainerProps |
ScrollViewProps | ScrollContainerProps |
ListViewProps | ListContainerProps |
TabViewProps | TabContainerProps |
PageViewProps | PageContainerProps |
ListPickerItem | ListPickerItemData |
DatePickerProps | DateTimePickerProps |
Removed props
MenuButton.type ('default' | 'warning' | 'error') has been removed — foreground color is now always onBackground:
// Before
<MenuButton type="error" leading="Logout" title="Sign Out" onPress={signOut} />
// After
<MenuButton leading="Logout" title="Sign Out" onPress={signOut} />
ButtonType.destructive has been removed — use 'error' instead:
// Before
<Button type="destructive" title="Delete" />
// After
<Button type="error" title="Delete" />
4. Update tsconfig paths (if using the example app pattern)
// Before
"paths": {
"@multinaire/multinaire-design": ["../build/index"]
}
// After
"paths": {
"@multinaire/ui": ["../build/index"]
}