Building Themable Mobile Applications with React Native

Software development Company

Building Themable Mobile Applications with React Native

Introduction

In today's blog post, we will explore the concept of building themeable mobile applications using React Native. We'll discuss how to create a white-label app that allows for easy customization of themes, templating, and module composition. By following this approach, you can save development time and resources while ensuring consistency across multiple applications. Let's dive in!

Problem: Building Similar Mobile Applications with Shared Features

In many cases, you may need to develop multiple mobile applications that share common features and functionalities while also having their unique branding and themes. For instance, a client may commission three mobile applications, each featuring different areas accessible via navigation tabs, custom themes and colors, and unique icons and display names. As a developer, it's crucial to find an efficient way to create these applications without duplicating code and ensure easy customization of themes and other branding elements.

Solution: Dynamic Generation of Themable Applications

To address this problem, we can leverage the power of React Native and employ a dynamic generation approach for themable applications. By following the steps outlined below, we can achieve the desired outcome:

1. Project Setup

To begin, initialize a new React Native project using the following command:

react-native init whitelabel

After project setup, we'll make some adjustments to ensure consistent bundle identifiers for both Android and iOS versions.

2. Module Composition

Conceptually, modules represent independent sections of an application, each offering different functionalities and information to the user. Instead of duplicating module code, we'll define modules as objects with unique names and corresponding React components. These modules will be stored in a modules directory.

Here's an example of defining a module:

import React from 'react';
import { Text, View } from 'react-native';

const FooComponent = () => (
   <View>
     <Text> Module Foo</Text>
   </View>
);

export default {
   name: 'Foo',
   Component: FooComponent,
};

We can create multiple modules following this pattern, such as Bar and Baz. To access these modules collectively, we'll create an index.js file in the modules directory:

import Bar from './Bar';
import Baz from './Baz';

export default [Foo, Bar, Baz];

We will keep things simple and just render all modules in one page, one below the other. We are going to do that in App.js

import { Text, View, SafeAreaView } from 'react-native';
import modules from './modules';
const styles = require('./theme')('App');
export default () => (
   <SafeAreaView style={{ flex: 1, backgroundColor: '#fff' }}>
     <Text>
       White-Label App
     </Text>
     <View>
       {modules.map(({ name, Component }) =>
           <Component key={name} />
       )}
     </View>
   </SafeAreaView>
); 

If we run the application, we should get something like

Untitled design (16).png

Nothing too fancy, but it gets the job done. Interestingly, we can render any combination of modules by simply changing the exported array in modules/index.js. For instance, exporting [Foo, Baz], [Baz, Bar] and []will produce, respectively, the following results.

Screenshot 2023-05-15 at 2.30.52 PM-2.png

This approach allows us to easily select and render any combination of modules in our application without modifying the components.

3. Theming and Styles

To enhance the visual appeal of our application, we'll introduce theming and styles. Instead of defining styles inline or duplicating them, we'll separate the styles from the components' logic. We'll create a theme folder alongside the modules directory.

For example, let's create a solarized-dark theme:It will contain two stylesheet files App.js and Module.js. The first one will contain styles for the main React component

import { StyleSheet } from 'react-native';

export default StyleSheet.create({
   container: {
       flex: 1,
       justifyContent: 'center',
       backgroundColor: '#002b36',
   },
   title: {
       paddingHorizontal: 16,
       color: '#657b83',
       fontSize: 20,
       fontWeight: 'bold',
   },
}); 

and the latter will style modules

import { StyleSheet } from 'react-native';
export default StyleSheet.create({
   container: {
       height: 100,
       borderWidth: 1,
       borderColor: '#657b83',
       margin: 16,
       justifyContent: 'center',
       alignItems: 'center',
   },
   text: {
       color: '#657b83',
   },
   accent: {
       color: '#268bd2',
       fontWeight: 'bold', 
},
});

To apply these styles, we'll make some changes to our components. For instance, in App.js:

import { Text, SafeAreaView, View } from 'react-native';
import modules from './modules';
import styles from './theme/solarized-dark/App';

export default () => (
   <SafeAreaView style={styles.container}>
     <Text style={styles.title}>White-Label App</Text>
     {modules.map((module) => (
       <View key={module.name}>
         <Text>{module.name}</Text>
         <module.Component />
       </View>
     ))}
   </SafeAreaView>
);

export default App; 

and Foo.js, Bar.js and Baz.js are modified as follows

import { Text, View } from 'react-native';
import styles from '../theme/solarized-dark/Module';
const FooComponent = () => (
   <View style={styles.container}>
     <Text style={styles.text}>
       Module <Text style={styles.accent}>Foo</Text>
     </Text>
   </View>
);
export default {
   name: 'Foo',
   Component: FooComponent,
}; 

Untitled design (17).png

4. Dynamic Theming

Now, we'll implement the dynamic theming functionality. We can achieve this by creating a ThemeProvider component that accepts a theme name as a prop. The ThemeProvider component will render its children components wrapped within a ThemeProviderContext.Provider, passing the selected theme as the context value.

import React, { createContext, useState } from 'react';

export const ThemeProviderContext = createContext();

export const ThemeProvider = ({ children }) => {
   const [theme, setTheme] = useState('solarized-light); // Default theme

   const changeTheme = (newTheme) => {
     setTheme(newTheme);
   };

   return (
     <ThemeProviderContext.Provider value={{ theme, changeTheme }}>
       {children}
     </ThemeProviderContext.Provider>
   );
}; 

Untitled design (18).png

Wrap the App component with the ThemeProvider in index.js:

import { AppRegistry } from 'react-native';
import { ThemeProvider } from './ThemeProvider';
import App from './App';

const Main = () => (
   <ThemeProvider>
     <App />
   </ThemeProvider>
);

AppRegistry.registerComponent(appName, () => Main); 

5. Theme Selection

To allow users to switch between themes, we can create a separate screen or settings panel. This screen will display a list of available themes and update the selected theme in the ThemeProvider context when a new theme is chosen. Here's an example of a theme selection screen:

import React, { useContext } from 'react';
import { View, Button, Text } from 'react-native';
import { ThemeProviderContext } from '../ThemeProvider';

const themes = ['solarized-dark', 'light', 'custom'];

const ThemeSelection = () => {
   const { changeTheme } = useContext(ThemeProviderContext);

   const handleThemeChange = (newTheme) => {
     changeTheme(newTheme);
   };

   return (
     <View>
       <Text>Select Theme:</Text>
       {themes.map((theme) => (
         <Button
           key={theme}
           title={theme}
           onPress={() => handleThemeChange(theme)}
         />
       ))}
     </View>
   );
};
export default ThemeSelection; 

Make sure to define the ThemeSelection screen as a navigable component and provide access to it from the main app.

Conclusion

By following this approach, you can easily create themable mobile applications using React Native. The modular structure allows for efficient code reuse, while the dynamic theming capability enables easy customization of themes and branding elements. With this setup, you can quickly build multiple applications with shared features while maintaining consistency and flexibility. Remember to explore additional possibilities, such as integrating a theming library like react-native-paper or allowing users to create custom themes. With React Native's flexibility, the possibilities are endless. Happy theming and happy coding!

Software development Company
Jasimuddin Ansari

Hi there, I hope you enjoy reading this blog post. Thank you for your time.

agile software development company

Contact Us

We’re looking forward to hear from you! Let’s make the next big product together.

Software Development Company in Aligarh

India

B3, HK Compound, NH 509, Sikandarpur, Chherat, Uttar Pradesh 202002

Phone +91 9045708272

Email: [email protected]

Software Development Company in UK

UK

16 Maryatt Avenue, London, U.K.

+447342893185

[email protected]

Software Development Company in Australia

Riyadh

AlSulymaniah - Prince Mamdouh Street AlSafwa Building, Gate 1

+966-597 238 206

[email protected]

Sofyrus Technologies Company
Startup India
Good Firms
MicroSoft for Startup
ISO

© 2019-2023 Sofyrus Technologies | All Right Reserved |