Multi Tenanted Content changes in React
Tags: multi, tenancy, react
Published: 2019-05-05 12:53:15

---
title: Multi Tenanted Content changes in React
published: true
description: Tutorial on how to change string & html content in a React front end based on tenant
tags: multi, tenancy, react
---

# Introduction

We have a number of tenants who require the same basic functionality but use slightly different terminology leading to a requirement for our user interface to vary based on which tenant is being used. It turns out this is very easy to do in React with the assistance of [React-Intl](https://github.com/yahoo/react-intl).

## Notes

I use yarn as my primary package manager so expect yarn commands to be quoted throughout. If you use npm or something else you'll need to translate the commands. If this is more complicated than using `npm install ...` instead of `yarn add ...` I'll try to add more information.

I'm going to be using Windows, VS Code, PowerShell for my development work, but it is my intention that this tutorial will apply regardless of what comparable tools you will use.

## Setup

You can retrieve the [project files](https://github.com/wozzo/react-tenancy) from Github. Starting at the second commit in the project we have a simple form with no content management in place. All the strings are hard coded parts of the components. We're going to work through from here to change that, or you can just look at the finished thing.

![A simple form with some strings to customise](https://thepracticaldev.s3.amazonaws.com/i/kq1q8du3o4zwjzu756on.png)

To compile and view the page with the dev server navigate to the directory and run `yarn start`. This will watch for file changes and refresh the browser window with the latest version.

# React-Intl

React-Intl is primarily intended for internationalising your app, but it turns out we can also use it to achieve the above without compromising it's original purpose if you also require internationalisation.

## Adding react-intl

Add react-intl to your project by running `yarn add react-intl`. We're now going to add react-intl to our app so that the components can use it for managing the string content.

In `index.js` add the following line
```javascript
import { IntlProvider } from 'react-intl';
```
We then need to wrap our entire app in the `IntlProvider` HOC. 
```javascript
<IntlProvider locale="en">
    <App />
</IntlProvider>
```

## Our first managed string

Now that we've added react-intl we can use it with the `FormattedMessage` component that is provided by react-intl. In `ExampleForm.jsx` add the following
```javascript
import {FormattedMessage} from 'react-intl'
```

The first string we're going to change here is the label for the text input. Currently it is "Procedure name". It still will be by the time we're done but it will be being managed by react-intl enabling us to change it.

Add a new `const` above the `ExampleForm` as follows
```javascript
const messages = {
  procedureNameLabel: {
    id: "ExampleForm.ProcedureName.Label",
    defaultMessage: "Procedure Name",
    description: "Label text for the procedure name input text box on the Example form"
  }
}
```
(Note: The description is optional, but you must provide a unique `id` and `defaultMessage` for all messages you use with `react-intl`).

Now replace the text of "Procedure Name" in the label markup so that it looks like the following
```javascript
<label htmlFor="procedureName">
    <FormattedMessage {...messages.procedureNameLabel} />
</label>
```
The end result should be appear exactly the same as before. It isn't quite the same since the FormattedMessage renders the text within a `<span />`. Inspecting the html should reveal the following
```html
<label for="procedureName">
    <span>Procedure Name</span>
</label>
```
This may mean you need some changes to your css you can use the following alternative approach

## Plain formatted message

Create a new file called `PlainFormattedMessage.jsx` and put the following in to it
```javascript
import React from 'react';
import { FormattedMessage } from 'react-intl'

const PlainFormattedMessage = (props) => 
    <FormattedMessage {...props}>
        {(message) => message }
    </FormattedMessage>

export default PlainFormattedMessage
```
This will render the message without the `<span />` tag surrounding it. You can use it be replacing `import { FormattedMessage } from 'react-intl'` with `import PlainFormattedMessage from './PlainFormattedMessage'` and changing `<FormattedMessage ...>` to `<PlainFormattedMessage ...>` in the `ExampleForm.jsx` file.

## Changing strings in attributes

The above approaches work well where the string is the child of a tag, but for situations where we want to change the text of an attribute we need to use a new component in a very similar way to the `PlainFormattedMessage`. The example we're going to use here is the `value` attribute of the submit button. Add a new value to the messages object for the text.
```javascript
exampleFormSubmitProcedureButtonText: {
    id: "ExampleForm.SubmitProcedure.ButtonText",
    defaultMessage: "Submit procedure"
}
```
Then replace the `<input ... />` with the following
```javascript
<FormattedMessage {...messages.exampleFormSubmitProcedureButtonText}>
    {(message) => <input type="submit" value={message} />}
</FormattedMessage>
```
Again if we've done everything right it should still compile and be rendering exactly the same is it was before. It's a lot of work for no changes so far, but our next steps are where we'll override the defaults and start to bring value from these changes.

Note: You probably want to move this functionality out to a separate component. We have an `<Input />` component specifically for rendering our `<input />`s and have included this functionality there by passing the message as a property to that component, as well as a tooltip attribute which also uses a managed string.

## Changing the strings

So our new tenant requires us to label the `procedureName` input text box with the text "Operation Name" instead of "Procedure Name". In fact everywhere where we've said "Procedure" they want us to say "Operation" so we override the current default messages. We can do this by creating a file that has all of the overriden strings in it. You don't have to retrieve these overrides from a file, you could use `fetch()` and retrieve them at run time if that suits your use case.

Create a new file and call it something that identifies the tenant. I'm going with `op-tenant.json` for my example.
The key's should correspond to the `id` of the message we wish to override, while the value should be the new text, so for our two string's so far it should look like this:
```json
{
    "ExampleForm.ProcedureName.Label": "Operation Name",
    "ExampleForm.SubmitProcedure.ButtonText": "Submit Operation"
}
```
In `index.js` we'll need to import/retrieve the tenant message overrides. They then need to be passed to the `IntlProvider` on the `messages` attribute if that tenant has been selected. I'm going to assume you already have some means of determining your tenant and in the example I'm just going to set it using a constant string value. Now we need a method which will return the overrides if the tenant matches.
```javascript
import opTenantMessages from './messages/op-tenant.json'

const tenant = "normal-tenant"
const getMessages = () => {
    if (tenant && tenant === "op-tenant")
        return opTenantMessages
    return {}
}
```
Then to use it we change the `<IntlProvider>` so that it uses this method
```javascript
<IntlProvider locale="en" messages={getMessages()}>
```
With the above our site should still render as it was before.
![A simple form with some strings to customise](https://thepracticaldev.s3.amazonaws.com/i/kq1q8du3o4zwjzu756on.png)
But just by changing the tenant value to "op-tenant" it should update the strings
![A simple form with some strings to customise](https://thepracticaldev.s3.amazonaws.com/i/yhsu3pr0wcvwymj8rqh4.png)

## Final thoughts

I recommend you replace all string content with messages whether your app is tenant or international or not. One day one of these might become a requirement and you'll be glad that the foundations are already in place. It also means that string content isn't cluttering your markup.

The `FormattedMessage` used here is just one of the components provided by `react-intl`. Most of the others are more useful for internationalisation, such as managing currency symbols, etc. Another which can be particularly useful for tenancy applications is `FormattedHtmlMessage` which allows the message to contain HTML markup which can then be overriden by tenant.

String interpolation or rather template strings are also supported by `react-intl` should you need to change a string made of other variables. For example error messages which need to change based on the field with the error. If the defaultMessage contained a template string resembling the following
```javascript
`The {fieldName} is a required field`
```
We would need to provide a `fieldName` to the component that is rendering the message as follows
```
<FormattedMessage {...messages.errorMessage} values={ fieldName: "Date of birth"} />
```
This would then output "The Date of birth is a required field". I'll leave it as an exercise for the reader to figure out how to also override the `fieldName` with a `react-intl` controlled string.

Hopefully I've provided you with enough to enable you to have your application changing content based on the tenant.