Code Screens enable you to seamlessly integrate custom native React components into your remotely configured Muta flows. This powerful feature allows you to combine the flexibility of no-code flow management with the full capabilities of native development.
Overview
Code Screens act as placeholders in your Muta flows that are replaced with native React components at runtime. This enables you to:
Add authentication screens to your onboarding flows
Integrate payment processing directly in your flows
Include complex native UI that requires custom logic
Maintain remote configurability while using native code
How It Works
Create a Code Screen
In the Muta web editor, add a “Code Screen” to your flow and give it a unique name (e.g., “Login Screen”, “Payment Form”)
Configure Navigation
Set up the continue and back navigation destinations for your code screen
Inject Components
Pass your React components when displaying the placement in your app
Implementation
Basic Setup
Pass your custom components when calling displayPlacement
:
import { Muta } from '@mutalabs/react-native-muta' ;
import { LoginScreen } from './screens/LoginScreen' ;
import { PaymentScreen } from './screens/PaymentScreen' ;
Muta . displayPlacement ({
placementId: 'onboarding' ,
bgColor: '#000000' ,
presentationType: 'none' ,
injectedScreens: [
{
screenName: 'Login Screen' , // Must match the name in Muta editor
component: LoginScreen ,
},
{
screenName: 'Payment Form' ,
component: PaymentScreen ,
},
],
});
Component Interface
Your injected components receive the following props:
interface CodeScreenProps {
onContinue : () => void // Navigate to configured continue destination
onBack : () => void // Navigate to configured back destination
variables : any [] // Current flow variables
screenId : string // Unique screen ID
screenIndex : number // Screen position in flow
}
Example Component
Here’s a complete example of a login screen component:
import React , { useState } from 'react' ;
import { View , TextInput , Button , StyleSheet , Text } from 'react-native' ;
function LoginScreen ({ onContinue , onBack , variables } : CodeScreenProps ) {
const [ email , setEmail ] = useState ( '' );
const [ password , setPassword ] = useState ( '' );
const [ error , setError ] = useState ( '' );
const [ loading , setLoading ] = useState ( false );
const handleLogin = async () => {
setError ( '' );
setLoading ( true );
try {
// Your authentication logic
const response = await fetch ( 'https://api.example.com/login' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({ email , password }),
});
if ( response . ok ) {
const data = await response . json ();
// Store auth token, update user state, etc.
await AsyncStorage . setItem ( 'authToken' , data . token );
// Navigate to the next screen in the flow
onContinue ();
} else {
setError ( 'Invalid email or password' );
}
} catch ( err ) {
setError ( 'Network error. Please try again.' );
} finally {
setLoading ( false );
}
};
return (
< View style = { styles . container } >
< Text style = { styles . title } > Welcome Back </ Text >
< TextInput
style = { styles . input }
value = { email }
onChangeText = { setEmail }
placeholder = "Email"
keyboardType = "email-address"
autoCapitalize = "none"
editable = { ! loading }
/>
< TextInput
style = { styles . input }
value = { password }
onChangeText = { setPassword }
placeholder = "Password"
secureTextEntry
editable = { ! loading }
/>
{ error ? < Text style = { styles . error } > { error } </ Text > : null }
< Button
title = { loading ? "Logging in..." : "Login" }
onPress = { handleLogin }
disabled = { loading || ! email || ! password }
/>
< Button
title = "Back"
onPress = { onBack }
disabled = { loading }
/>
</ View >
);
}
const styles = StyleSheet . create ({
container: {
flex: 1 ,
padding: 20 ,
justifyContent: 'center' ,
},
title: {
fontSize: 24 ,
fontWeight: 'bold' ,
marginBottom: 30 ,
textAlign: 'center' ,
},
input: {
borderWidth: 1 ,
borderColor: '#ddd' ,
padding: 15 ,
marginBottom: 15 ,
borderRadius: 8 ,
},
error: {
color: 'red' ,
marginBottom: 15 ,
textAlign: 'center' ,
},
});
Animations
Code screens automatically animate in and out matching your flow’s configured animations:
Entry Animation : Matches the animation used when navigating TO the code screen
Exit Animation : Uses the configured continue/back animation settings
Seamless Transitions : Native screens blend smoothly with your flow screens
Use Cases
Authentication Flows
Integrate login, signup, or authentication screens directly into your onboarding:
injectedScreens : [
{ screenName: 'Login' , component: LoginScreen },
{ screenName: 'Signup' , component: SignupScreen },
{ screenName: 'Verify Email' , component: VerifyEmailScreen },
]
Payment Integration
Add payment processing without breaking the flow experience:
injectedScreens : [
{ screenName: 'Payment Method' , component: PaymentMethodScreen },
{ screenName: 'Billing Details' , component: BillingDetailsScreen },
{ screenName: 'Confirm Purchase' , component: ConfirmPurchaseScreen },
]
Handle multi-step forms or complex data entry:
injectedScreens : [
{ screenName: 'Profile Setup' , component: ProfileSetupScreen },
{ screenName: 'Preferences' , component: PreferencesScreen },
{ screenName: 'Location Permissions' , component: LocationPermissionScreen },
]
Best Practices
Use descriptive, unique names for your code screens
Keep names consistent between the Muta editor and your code
Avoid special characters in screen names
Always handle errors gracefully in your components
Provide clear feedback to users
Consider offering retry options for network failures
Always call onContinue()
or onBack()
to maintain flow continuity
Disable navigation buttons during async operations
Consider confirmation dialogs for destructive back actions
Troubleshooting
Screen names must match exactly between the Muta editor and your injected screens configuration. A mismatch will result in the code screen not displaying.
Common Issues
Code screen not appearing:
Verify the screen name matches exactly (case-sensitive)
Ensure the component is properly imported
Check that injectedScreens is passed to displayPlacement
Navigation not working:
Confirm you’re calling onContinue() or onBack()
Check that navigation destinations are configured in the editor
Ensure no JavaScript errors are preventing execution
Animation issues:
Verify presentationType is set appropriately
Check that animation durations are reasonable (200-500ms)
Ensure components render quickly to avoid animation lag
Advanced Usage
Accessing Flow Variables
Code screens can read and react to flow variables:
function PaymentScreen ({ variables , onContinue } : CodeScreenProps ) {
// Find specific variable by ID
const planType = variables . find ( v => v . id === 'selected_plan' )?. value ;
const userEmail = variables . find ( v => v . id === 'user_email' )?. value ;
// Use variables to customize the screen
const price = planType === 'premium' ? '$9.99' : '$4.99' ;
// ... rest of component
}
Sequential Code Screens
You can navigate directly from one code screen to another:
// In Muta editor: Login Screen → Verification Screen → Welcome Screen
injectedScreens : [
{ screenName: 'Login Screen' , component: LoginScreen },
{ screenName: 'Verification Screen' , component: VerificationScreen },
// Welcome Screen is a regular Muta screen
]
The SDK handles transitions smoothly between consecutive code screens without any special configuration.