How to set default font family in React Native?
Asked Answered
D

16

153

Is there an equivalent to this CSS in React Native, so that the app uses the same font everywhere ?

body {
  font-family: 'Open Sans';
}

Applying it manually on every Text node seems overly complicated.

Departmentalize answered 7/2, 2016 at 15:57 Comment(1)
Is there a way to set a font globally in React Native? has a few additional approaches.Marte
A
106

The recommended way is to create your own component, such as MyAppText. MyAppText would be a simple component that renders a Text component using your universal style and can pass through other props, etc.

https://reactnative.dev/docs/text#limited-style-inheritance

Advisement answered 8/2, 2016 at 4:2 Comment(5)
Thanks that's exactly what I needed. Seems like I didn't grasp the component approach deeply enough yet :)Departmentalize
One thing that's not super clear from the docs is how to pass through properties in your component and to respect styles on your component. You can do so like this: gist.github.com/neilsarkar/c9b5fc7e67bbbe4c407eec17deb7311eWendell
@NeilSarkar One problem with that gist example is that the style is generated in the constructor. As a result, if the style prop changes, you would want it to re-render, but in this case it won't. It should be handled in render() instead of the constructor. Using hooks with useMemo could also help if efficiency is important. Alternatively, if you want to keep it in the constructor, it's important to add a componentDidUpdate logic that updates this.style when the component updates due to a style prop change.Heintz
good point, thanks! looks like someone added a refactored version to the gist too that combines the styles in the render method (of a pure component, in their case)Wendell
For me, positioning children isn't working. For example alignSelf: "center" does not work ...Elbring
E
73

There was recently a node module that was made that solves this problem so you don't have to create another component.

https://github.com/Ajackster/react-native-global-props

https://www.npmjs.com/package/react-native-global-props

The documentation states that in your highest order component, import the setCustomText function like so.

import { setCustomText } from 'react-native-global-props';

Then, create the custom styling/props you want for the react-native Text component. In your case, you'd like fontFamily to work on every Text component.

const customTextProps = { 
  style: { 
    fontFamily: yourFont
  }
}

Call the setCustomText function and pass your props/styles into the function.

setCustomText(customTextProps);

And then all react-native Text components will have your declared fontFamily along with any other props/styles you provide.

Everyplace answered 10/12, 2016 at 13:7 Comment(7)
The idiomatic method to use component composition seems like a better choice, although this is a cool hack.Fortnight
When the Text component doesn't support changing default fonts out of the box, this solution becomes much better. I would much rather add a global control in one place and use the native components than make a wrapper component for every detail that true native apps provide.Raviv
I hesitated between above 2 solutions, actually I hate to install unofficial plugins cause react-native itself continues to change, but finally I choose this one as it can really save me huge amount of time. Thanks!Sentient
SO I need to call <Text style={styles.text}> ?? It's not perfect solution like thats body {font-family: 'Open Sans';} have any update solution ??Madrigalist
No you don't need to do Text style={styles.text}>. You just need to declare your custom props somewhere in your application and it will be applied to all of your Text components. It's very similar to body {font-family: ....}Everyplace
This is golden approach, but how can this be done in RN Expo project?Merkel
IMO react-native-global-props is less of a hack than wrapping every single component and having to maintain those wrappers. Thanks @Everyplace for sharing your very useful library.Scheer
B
39

For React Native 0.56.0+ check if defaultProps is defined first:

Text.defaultProps = Text.defaultProps || {}

Then add:

Text.defaultProps.style =  { fontFamily: 'some_font' }

Add the above in the constructor of the App.js file (or any root component you have).

In order to override the style you can create a style object and spread it then add your additional style (e.g { ...baseStyle, fontSize: 16 })

Brunk answered 21/12, 2017 at 12:51 Comment(14)
Maybe the defaultProps didn't exist when all the other answers were written but this seem to be the way to do it now.Carlyle
Unfortunately, it won't work if we override style prop, say, to tweak styles of particular Text componentsFrontality
True but you can work around this , create the common style as an object and when ever you want some custom font just pass to the component an array that contains that object + yourNewStyleObject @FrontalityBrunk
@Brunk thanks! It'll work, although adds small overhead :)Frontality
I've found that I can use spread operator to combine text styles and avoid creating arrays in render js textStyle: { ...baseStyle, fontSize: 16 } Frontality
There is a problem there. If someone then define the style prop in the Text component, the default font is going to be replaced.Gnaw
Cannot set property 'style' of undefinedVickers
@jamesmurphy probably now you have to check first if its there: Text.defaultProps = Text.defaultProps || {} Text.defaultProps.style = { ... }Brunk
Yes that got rid of the error, but does not appear to work on app (font does not change)....Im testing on Android and using RN 0.59.5Vickers
constructor in App.js (base component)Vickers
it's 2019 and it's working perfectly. just remember in android you can't use "-" in file names. define your font file names something like font_name.ttf.Swagman
This is one way of doing it @AniruddhaShevleBrunk
@A-J-A: I know. My question still remains the same! Is this the right way to do it? What do you think?Linzer
It depends on your approach because this has a bit of drawbacks ( styles can get overridden then you'll have to spread that object into the component style prop ). If you don't face that problem, this approach is simple and straightforward. I can't really say that this is the RIGHT way because I would be indirectly saying other ways are wrong. @AniruddhaShevleBrunk
L
29

You can override Text behaviour by adding this in any of your component using Text:

let oldRender = Text.prototype.render;
Text.prototype.render = function (...args) {
    let origin = oldRender.call(this, ...args);
    return React.cloneElement(origin, {
        style: [{color: 'red', fontFamily: 'Arial'}, origin.props.style]
    });
};

Edit: since React Native 0.56, Text.prototypeis not working anymore. You need to remove the .prototype :

let oldRender = Text.render;
Text.render = function (...args) {
    let origin = oldRender.call(this, ...args);
    return React.cloneElement(origin, {
        style: [{color: 'red', fontFamily: 'Arial'}, origin.props.style]
    });
};
Leathers answered 17/11, 2017 at 12:32 Comment(9)
That's a great solution but you have to change: [origin.props.style, {color: 'red', fontFamily: 'Arial'}] ->[{color: 'red', fontFamily: 'Arial'}, origin.props.style] Otherwise you will override the custom style setted in the componentCombine
Worked best. Text.prototype.render doesn't work anymore, Text.render does !Scandent
how to avoid icons inheriting the same?Fed
I agree with @IaconisSimone Best approach to set fontFamily and to be sure not to override custom stylesVc
Do I need to restart the app, if I want to make it dynamically ?Gillis
I tried the same thing for TextInput but it didn't work :/ any ideas?Rebel
This is the way to goImbecile
But this also changes some of the fonts in the warning and error boxes of RN in dev mode. The RN code does not specifically sets text color on some of its renderings. So be careful with custom colours here.Tuberous
this doens't work anymoreLomasi
S
21

With React-Native 0.56, the above method of changing Text.prototype.render does not work anymore, so you have to use your own component, which can be done in one line!

MyText.js

export default props => <Text {...props} style={[{fontFamily: 'Helvetica'}, props.style]}>{props.children}</Text>

AnotherComponent.js

import Text from './MyText';

...
<Text>This will show in default font.</Text>
...
Shearin answered 4/7, 2018 at 19:54 Comment(2)
@FancyJohn It will now with hooks and useRef. reactjs.org/docs/hooks-reference.html#userefDramatization
Text.prototype.render has changed to Text.render.Antiquity
A
11

Add this function to your root App component and then run it from your constructor after adding your font using these instructions. https://medium.com/react-native-training/react-native-custom-fonts-ccc9aacf9e5e

import {Text, TextInput} from 'react-native'

SetDefaultFontFamily = () => {
    let components = [Text, TextInput]

    const customProps = {
        style: {
            fontFamily: "Rubik"
        }
    }

    for(let i = 0; i < components.length; i++) {
        const TextRender = components[i].prototype.render;
        const initialDefaultProps = components[i].prototype.constructor.defaultProps;
        components[i].prototype.constructor.defaultProps = {
            ...initialDefaultProps,
            ...customProps,
        }
        components[i].prototype.render = function render() {
            let oldProps = this.props;
            this.props = { ...this.props, style: [customProps.style, this.props.style] };
            try {
                return TextRender.apply(this, arguments);
            } finally {
                this.props = oldProps;
            }
        };
    }
}
Annabell answered 3/1, 2018 at 4:52 Comment(5)
This is exactly what I was looking for, didn't want to install anything more.Resolvent
If my App.js mainly consists of const App = StackNavigator({...}) and export default App where exactly would I place this code as I do not think I can use a constructor here?Applegate
I have added my own question here: #50081542Applegate
Why constructor over componentDidMount?Signification
This failed to work for me starting with RN0.67, however adding a arguments[0] = props; before the try block fixed it for me.Hurleigh
G
6

Super late to this thread but here goes.

TLDR; Add the following block in your AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

 ....
    // HERE: replace "Verlag" with your font
  [[UILabel appearance] setFont:[UIFont fontWithName:@"Verlag" size:17.0]];
  ....
}

Walkthrough of the whole flow.

A few ways you can do this outside of using a plugin like react-native-global-props so Ill walk you though step by step.

Adding fonts to platforms.

How to add the font to IOS project

First let's create a location for our assets. Let's make the following directory at our root.

```

ios/
static/
       fonts/

```

Now let's add a "React Native" NPM in our package.json

  "rnpm": {
    "static": [
   "./static/fonts/"
    ]
  }

Now we can run "react-native link" to add our assets to our native apps.

Verifying or doing manually.

That should add your font names into the projects .plist (for VS code users run code ios/*/Info.plist to confirm)

Here let's assume Verlag is the font you added, it should look something like this:

     <dict>
   <plist>
      .....
      <key>UIAppFonts</key>
      <array>
         <string>Verlag Bold Italic.otf</string>
         <string>Verlag Book Italic.otf</string>
         <string>Verlag Light.otf</string>
         <string>Verlag XLight Italic.otf</string>
         <string>Verlag XLight.otf</string>
         <string>Verlag-Black.otf</string>
         <string>Verlag-BlackItalic.otf</string>
         <string>Verlag-Bold.otf</string>
         <string>Verlag-Book.otf</string>
         <string>Verlag-LightItalic.otf</string>
      </array>
      ....    
</dict>
</plist>

Now that you mapped them, now let's make sure they are actually there and being loaded (this is also how you'd do it manually).

Go to "Build Phase" > "Copy Bundler Resource", If it didn't work you'll a manually add under them here.

1_uuz0__3kx2vvguz37bhvya

Get Font Names (recognized by XCode)

First open your XCode logs, like:

XXXX

Then you can add the following block in your AppDelegate.m to log the names of the Fonts and the Font Family.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    .....


  for (NSString* family in [UIFont familyNames])
  {
    NSLog(@"%@", family);
    for (NSString* name in [UIFont fontNamesForFamilyName: family])
    {
      NSLog(@" %@", name);
    }
  }

  ...
}

Once you run you should find your fonts if loaded correctly, here we found ours in logs like this:

2018-05-07 10:57:04.194127-0700 MyApp[84024:1486266] Verlag
2018-05-07 10:57:04.194266-0700 MyApp[84024:1486266]  Verlag-Book
2018-05-07 10:57:04.194401-0700 MyApp[84024:1486266]  Verlag-BlackItalic
2018-05-07 10:57:04.194516-0700 MyApp[84024:1486266]  Verlag-BoldItalic
2018-05-07 10:57:04.194616-0700 MyApp[84024:1486266]  Verlag-XLight
2018-05-07 10:57:04.194737-0700 MyApp[84024:1486266]  Verlag-Bold
2018-05-07 10:57:04.194833-0700 MyApp[84024:1486266]  Verlag-Black
2018-05-07 10:57:04.194942-0700 MyApp[84024:1486266]  Verlag-XLightItalic
2018-05-07 10:57:04.195170-0700 MyApp[84024:1486266]  Verlag-LightItalic
2018-05-07 10:57:04.195327-0700 MyApp[84024:1486266]  Verlag-BookItalic
2018-05-07 10:57:04.195510-0700 MyApp[84024:1486266]  Verlag-Light

So now we know it loaded the Verlag family and are the fonts inside that family

  • Verlag-Book
  • Verlag-BlackItalic
  • Verlag-BoldItalic
  • Verlag-XLight
  • Verlag-Bold
  • Verlag-Black
  • Verlag-XLightItalic
  • Verlag-LightItalic
  • Verlag-BookItalic
  • Verlag-Light

These are now the case sensitive names we can use in our font family we can use in our react native app.

Got -'em now set default font.

Then to set a default font to add your font family name in your AppDelegate.m with this line

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

 ....
    // ADD THIS LINE (replace "Verlag" with your font)

  [[UILabel appearance] setFont:[UIFont fontWithName:@"Verlag" size:17.0]];
  ....
}

Done.

Gangboard answered 7/5, 2018 at 19:14 Comment(2)
The best approach, but is not working, anything related to the las update of RN 0.57?Allegorize
For android this answer worked for me: https://mcmap.net/q/57128/-how-to-set-default-font-family-for-entire-android-appRetrogression
J
4

For about a year I was using the react-native-global-props library mentioned in the 2nd comment to set a global font throughout the app. It was working great, and it felt better than using custom text components everywhere.

Suddenly the global font stopped working after I updated react native. I realized that the react-native-global-props library has not been updated since 2018.

I found this alternative package: react-native-simple-default-props https://www.npmjs.com/package/react-native-simple-default-props

Followed the docs exactly, and it worked perfectly after I was stuck on the best way to do this for several hours. Hope this helps someone.

Jejune answered 31/3, 2023 at 23:4 Comment(1)
Thanks for this! I only worry that it will also become out of date as it's already on 2 years since the last update. But for now (RN 0.72.6) seems to work as it should.Pecker
F
2

For android, this is works for me.

Create a folder called font inside

android\app\src\main\res\

Insert your font.ttf/.otf inside the font folder, Make sure the font name is lower case letters and underscore only.

eg:- rubik_regular.ttf

Add below line in

android\app\src\main\res\values\styles.xml

<item name="android:fontFamily">@font/font_name</item>

for example,

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
        <item name="android:fontFamily">@font/rubik_regular</item>
    </style>

    ...

</resources>

Make sure to re-run your app.

Also, we can add font size and font colors like this

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
        <item name="android:textSize">20sp</item>
        <item name="android:textColor">#008</item>
        <item name="android:fontFamily">@font/rubik_regular</item>
    </style>

    ...

</resources>
Falco answered 7/9, 2021 at 6:12 Comment(2)
Have you tested it? On RN 0.66 it breaks text layout.Electuary
I did a small project. "react-native": "^0.66.3"Falco
E
1

This answer used to work for me when I was using v0.63. But after upgrading react-native to v0.66.4 it broke.

I think the implementation of Text component has changed.

I came up with this solution:

    const oldTextRender = Text.render;

    Text.render = function(...args) {
        const origin = oldTextRender.call(this, ...args);
        const children = origin.props.children;

        if (typeof children === 'object') {
            return React.cloneElement(origin, {
                children: React.cloneElement(children, {
                    style: [ { fontFamily: 'CustomFontFamily' }, children.props.style ]
                })
            });
        }

        return React.cloneElement(origin, {
            style: [ { fontFamily: 'CustomFontFamily' }, origin.props.style ]
        });
    };

Notice that children prop may be an object, for example it might be a LogBoxMessage component. But the type of children prop of normal texts that are rendered on the screen are as type of string.

You may want to use a recursive function to apply the fontFamily to children

Excavate answered 23/2, 2022 at 9:38 Comment(0)
K
1

To have default font styling without styling LogBox, see:

import React from 'react'
import { Text } from 'react-native'

import yourStyle from './yourStyle'

export default function setGlobalFontFamily() {
  const oldTextRender = Text.render

  Text.render = function (...args) {
    const origin = oldTextRender.call(this, ...args)

    // RCTVirtualText is being used for LogBox while RCTText is being used for normal text
    if (origin.type === 'RCTVirtualText') {
      return origin
    }

    const children = origin.props.children
    if (typeof children === 'object') {
      return React.cloneElement(origin, {
        children: React.cloneElement(children, {
          style: [yourStyle, children.props.style]
        })
      })
    }

    return React.cloneElement(origin, {
      style: [yourStyle, origin.props.style]
    })
  }
}

Kudos answered 11/10, 2022 at 14:19 Comment(0)
S
0

That works for me: Add Custom Font in React Native

download your fonts and place them in assets/fonts folder, add this line in package.json

 "rnpm": {
"assets": ["assets/fonts/Sarpanch"]}

then open terminal and run this command: react-native link

Now your are good to go. For more detailed step. visit the link above mentioned

Swordcraft answered 11/6, 2019 at 5:12 Comment(0)
F
0

For React Native version ≥ 0.60, in your root file create a file called react-native.config.js and put the followings, then just run react-native link

module.exports = {
  assets: ["./assets/fonts"]
}
Fontainebleau answered 6/1, 2021 at 17:57 Comment(0)
S
0

You can try creating a theme for your application, you can use a React native ui library such as Nativebase to achieve what you are looking for and you can create your custom theme or component as well.

Saucy answered 1/12, 2023 at 6:4 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Despondency
A
-2

Add

"rnpm": {
  "assets": [
 "./assets/fonts/"
  ]
}

in package.json then run react-native link

Appanage answered 23/5, 2020 at 9:44 Comment(0)
E
-2

Set in package.json

"rnpm": {
  "assets": [
     "./assets/fonts/"
  ]
}

And link react-native link

Elite answered 1/8, 2020 at 5:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.