NativeBase and Moti share a common goal — bringing universality to application development while removing redundant workflows. Therefore, we decided to conduct an experiment that explores how an app-development team can leverage both platforms. We are going to do this by animating a button that changes padding when clicked.
Experiment Methodology
⭐ Moti, by Fernando Rojo, is a universal animation package for React Native. It uses reanimated for high performance and eliminates the need to write code for different platforms. ⭐ NativeBase provides universal UI components that focus on utility.
Our goal was to analyze the ease of animating a NativeBase component using Moti. We tested the Background Change animation using design tokens (aka. values or constants needed to construct a design system). The pseudo props of NativeBase made the code succinct.
Resources
🧰 Installation links for the two libraries:
⭐ Important characteristics of Moti to remember:
- Universal: works on all platforms
- 60 FPS animations run on the native thread
- Mount/unmount animations, like Framer Motion
- Powered by Reanimated 2
- Intuitive API
- Variant & keyframe animations
- Strong TypeScript support
- Highly-configurable animations
- Sequence animations
- Loop & repeat animations
- Web support
- Expo support
- Next.js support
Experiment
NativeBase is highly versatile. It is a UI component library that supports cross-platform development with a single codebase. Moti also shares a similar philosophy—write once, animate everywhere.
We wanted to test how these libraries complement each other by animating
padding
properties with help of Moti animation. NativeBase Factory was used to make our own custom component that could pair with Moti.Animation
The code below reflects how we have used a Nativebase component
Factory
to make our own custom component FactoryMotiNativeBaseView
⤵️const FactoryMotiNativeBaseView = Factory(MotiView);
const NBMotiView = ({
from,
to,
transition,
animate,
children,
...props
}: any) => {
const ConvertTokenizedStyleToStyle = (StyleObject) => {
const [style, ...restProp] = useStyledSystemPropsResolver(StyleObject);
return { ...style, ...restProp[0].dataSet };
};
Making the custom component was tricky. We had to find a way to use Moti’s animation props with NativeBase. Using
useStyledSystemPropsResolver
was the solution.This hook converted Moti’s animation props into props that Nativebase can accept. The code below details how we made it happen ⤵️
const NBMotiView = ({
from,
to,
transition,
animate,
children,
...props
}: any) => {
const ConvertTokenizedStyleToStyle = (StyleObject) => {
const [style, ...restProp] = useStyledSystemPropsResolver(StyleObject);
return { ...style, ...restProp[0].dataSet };
};
const resolvedProps = {
from: ConvertTokenizedStyleToStyle(from),
animate: ConvertTokenizedStyleToStyle(animate),
transition: { type: "timing", duration: 1000, delay: 10 },
};
The full animation of the video is shown below. ⤵️
Full Code Snippet of the Animation
import React, { useState } from "react";
//@ts-ignore
import { useStyledSystemPropsResolver } from "native-base/src/hooks/useStyledSystemPropsResolver.ts";
import { MotiView } from "moti";
import { Text, Factory, VStack, Pressable } from "native-base";
const FactoryMotiNativeBaseView = Factory(MotiView);
const NBMotiView = ({
from,
to,
transition,
animate,
children,
...props
}: any) => {
const ConvertTokenizedStyleToStyle = (StyleObject) => {
const [style, ...restProp] = useStyledSystemPropsResolver(StyleObject);
return { ...style, ...restProp[0].dataSet };
};
const resolvedProps = {
from: ConvertTokenizedStyleToStyle(from),
animate: ConvertTokenizedStyleToStyle(animate),
transition: { type: "timing", duration: 1000, delay: 10 },
};
return (
<Pressable
onPress={() => {
props.toggleHandler();
}}
>
<FactoryMotiNativeBaseView {...resolvedProps} {...props}>
{children}
</FactoryMotiNativeBaseView>
</Pressable>
);
};
export default function ExitBeforeEnter() {
const [visible, setVisible] = useState(true);
const toggleHandler = () => {
setVisible(!visible);
};
return (
<VStack justifyContent={"center"} alignItems="center" flex={1}>
<NBMotiView
from={{
p: visible? "5" : "10",
}}
animate={{
p: visible? "10" : "5",
}}
transition={{ type: "timing", duration: 1000, delay: 10 }}
bg="blue.200"
toggleHandler={toggleHandler}
>
<Text>Animated Button</Text>
</NBMotiView>
</VStack>
);
}
Verdict
NativeBase and Moti are terrific for creating animations on the web and native apps. It is cumbersome to add animation to an application with React Reanimated and animated V2 alone.
Moti simplifies the animator's workflow and NativeBase gives a great selection of UI components. It is a perfect match.