React-native: Using custom fonts in react-native project

Created on 6 May 2015  Â·  74Comments  Â·  Source: facebook/react-native

Looking to add custom fonts to my react-native app -- can't seem to find any documentation on this.

Locked

Most helpful comment

Any tips on how to use custom fonts in Android?

All 74 comments

@samuelcouch - same as how you would in a regular iOS app :smile:

Follow steps 1-4 here: http://codewithchris.com/common-mistakes-with-adding-custom-fonts-to-your-ios-app/

Then you can use that font family inside of your styles

Does RN support .woff fonts?

I think it's restricted to what IOS allows.

I've used free TTF's in my react native project.

Any tips on how to use custom fonts in Android?

@satya164 what have you tried? were you able to get anything working?

@ccheever All examples on the web suggest to extend the default Android TextView. There is also one using reflection which changes the font for the whole app (this worked). Though this is acceptable, I would also prefer is to be able to declare font families and use them in styles, so that I can use icon fonts etc.

Here is the link if you you just want to change font family for entire app - http://stackoverflow.com/questions/2711858/is-it-possible-to-set-font-for-entire-application

NOTE: I used sans instead of monospace.

I had custom fonts working in a native Android app. Trying to port it over to RN now and they aren't loading inside of <Text> components :(

@marcshilling can you describe in more detail what you tried? Do you still have .ttf files or similar in an assets/ folder? And how are you trying to use the custom fonts inside of RN? Just using the fontFamily style property on text nodes and referencing the fonts you are including?

@ccheever yes, exactly. I've tried putting the .ttf (and .otf) files in both /assets and /assets/fonts (I had to the do the latter on native). And then I declare text like so:

<Text style={{fontFamily: 'FuturaStd-ExtraBold'}}>Hello World</Text>

And just for the record - I'm using the same exact font files and declaring <Text> the exact same way in an iOS React Native project and they are working.

@marcshilling what do you mean with "I had to the do the latter on native", did you write "Typeface font = Typeface.createFromAsset" in the main activity?

This is how I got custom font working,

  1. Put your font files under assets/fonts
  2. Add the following files

FontsOverride.java

import java.lang.reflect.Field;
import android.content.Context;
import android.graphics.Typeface;

public final class FontsOverride {
    public static void setDefaultFont(Context context,
                                      String staticTypefaceFieldName, String fontAssetName) {
        final Typeface regular = Typeface.createFromAsset(context.getAssets(),
                fontAssetName);
        replaceFont(staticTypefaceFieldName, regular);
    }

    protected static void replaceFont(String staticTypefaceFieldName,
                                      final Typeface newTypeface) {
        try {
            final Field staticField = Typeface.class
                    .getDeclaredField(staticTypefaceFieldName);
            staticField.setAccessible(true);
            staticField.set(null, newTypeface);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

MyApplication.java

import android.app.Application;

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        FontsOverride.setDefaultFont(this, "DEFAULT", "fonts/Custom-Font-Regular.ttf");
        FontsOverride.setDefaultFont(this, "SANS_SERIF", "fonts/Custom-Font-Regular.ttf");

        // You can also use "MONOSPACE" and "SERIF", but "DEFAULT" and "SANS_SERIF" is all you need
        FontsOverride.setDefaultFont(this, "MONOSPACE", "fonts/Custom-Font-Monospace.ttf");
        FontsOverride.setDefaultFont(this, "SERIF", "fonts/Custom-Font-Serif.ttf");
    }
}

res/values/styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        ...
        <item name="android:typeface">sans</item>
    </style>

</resources>

Finally, in the <application> field of your AndroidManifest.xml, add the android:theme and android:name properties,

    <application
      ...
      android:name=".MyApplication"
      android:theme="@style/AppTheme"
      ...
      >

@satya164, you saved my day, i'm going going to try this tonight.
Thanks!
Geo

On Sun, Sep 20, 2015 at 4:36 AM, Satyajit Sahoo [email protected]
wrote:

This is how I got custom font working,

  1. Put your font files under assets/fonts
  2. Add the following files

_FontsOverride.java_*

import java.lang.reflect.Field;import android.content.Context;import android.graphics.Typeface;
public final class FontsOverride {
public static void setDefaultFont(Context context,
String staticTypefaceFieldName, String fontAssetName) {
final Typeface regular = Typeface.createFromAsset(context.getAssets(),
fontAssetName);
replaceFont(staticTypefaceFieldName, regular);
}

protected static void replaceFont(String staticTypefaceFieldName,
                                  final Typeface newTypeface) {
    try {
        final Field staticField = Typeface.class
                .getDeclaredField(staticTypefaceFieldName);
        staticField.setAccessible(true);
        staticField.set(null, newTypeface);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

}

_MyApplication.java_

import android.app.Application;

public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();

    FontsOverride.setDefaultFont(this, "DEFAULT", "fonts/Custom-Font.ttf");
    FontsOverride.setDefaultFont(this, "SANS_SERIF", "fonts/Custom-Font.ttf");
}

}

_res/values/styles.xml_

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/primary</item>
    <item name="colorPrimaryDark">@color/primary_dark</item>
    <item name="colorAccent">@color/accent</item>
    <item name="android:typeface">sans</item>
</style>

—
Reply to this email directly or view it on GitHub
https://github.com/facebook/react-native/issues/1167#issuecomment-141730183
.

Met vriendelijk groet,
Gerald Olivero
+31634771782
geolivero.com

@geolivero No problem, I had left out the part where you have to change the AndroidManifest.xml, added it to the post now.

@satya164 what if I need multiple, different custom fonts in my app? You approach seems to simply replace the default font with a single custom font.

@marcshilling Yeah, that will be immensely useful, e.g. - icon fonts. But I've not managed to figure that out yet.

@satya164 I've just added Android support to react-native-icons so you can use icon fonts.

As for custom fonts in general, CustomStyleSpan.java is where typefaces are currently set in React Native Android. For fontFamily to properly work with a custom font, RN would need some way to register a custom font family name with a font file in /assets when setting up the ReactInstanceManager.

Something like:

 mReactInstanceManager = ReactInstanceManager.builder()
  .setApplication(getApplication())
  .setBundleAssetName("index.android.bundle")
  .setJSMainModuleName("index.android")
  .addPackage(new MainReactPackage())

  // Add a font family name associated to a font file in /assets
  .addTypeFace("CustomFont", "Custom-Font.ttf")  

  .setUseDeveloperSupport(BuildConfig.DEBUG)
  .setInitialLifecycleState(LifecycleState.RESUMED)
  .build();

@corymsmith Awesome man. Thanks a ton.

// Add a font family name associated to a font file in /assets .addTypeFace("CustomFont", "Custom-Font.ttf")

Does it work with 0.11.4? For me compiler cannot find this method on Builder instance

@wizardzloy It's just a concept.

@wizardzloy I was merely proposing a way to handle that but it hasn't been implemented

@corymsmith @satya164 Oh, I see. So there is no working solution for multiple custom fonts so far?

There is an open PR that aims to solve this problem. Hope it will be merged soon
https://github.com/facebook/react-native/pull/3800

Has anyone else had difficulty using the custom fonts on their device? I'm using a font 'GOUDIAC' for Sanskrit transliteration and while it works fine in the Simulator it doesn't load in the actual device

I just tried a new font using the @satya164 method and some words magically disappeared in my app, it seems that views doesn't calculate the sufficient space to display them. Does anyone have encountered the same problem?

@fxhereng Custom font support has been added in React Native - https://github.com/facebook/react-native/commit/bfeaa6a4f531cfc18c097bc9ffb6a8dbe3ddc702

You can try 0.16.0-rc to use it.

@satya164 I still have a problem using that code..
when I change the font setting on the device, my font got changed too.
Any idea?

@ericchris Did you try 0.16.0-rc?

That code might not work on few devices.

@satya164 Can you give a sample code for using the custom fonts ? i'm using 0.16.0-rc and i added the fonts to assets/fonts but i cant get them to work.

@turka50 - the font file name should be the same as the font name and should contain only lowercase letter and underscores, e.g.:

{ fontFamily: 'font_name' }

projectfolder/android/app/src/main/assets/fonts/font_name.ttf

@richarddewit - This is the folder where my files are : \android\appsrcmain\assets\fonts

and the files are :
image

and markup finaly is :

image

But the text doesn't get affected at all, any ideas ?

@turka50:

  • Did you run react-native run-android?
  • Do you have the latest file projectfolder/android/app/react.gradle and a reference to it in projectfolder/android/app/build.gradle?
  • Do you have any typeface specified in projectfolder/android/app/src/main/res/values/styles.xml? (If so remove it)

@richarddewit I think the issue is that 0.16.0-rc is not properly installed, I'm getting a weird error saying -
image

Any ideas ?

@turka50 Check if you have compile "com.facebook.react:react-native:0.16.+" in projectfolder/android/app/build.gradle

@richarddewit Yes i do. I'm getting this error also -
image

@turka50 Delete the folders

  • projectfolder/android/.gradle
  • projectfolder/android/app/build

and rebuild your project using react-native run-android

Also your font is not in assets/fonts/

@richarddewit Tried what you suggested , Still not working. The weird thing is that i deleted that folder and there are no fonts at all but it still shows that error...

@turka50 It seems that it's referencing to main/res/assets/ instead of main/assets/. Can you check there?

@richarddewit Ok that was the error ... moving on to the next error :)
image

@turka50 Known issue with ES6 imports. The fix should land in 0.16 https://github.com/facebook/react-native/commit/ffea7793aff0961ebc22007d650ce36f7c2e61cb

@corymsmith I've just read your snippet to add a custom font here https://github.com/facebook/react-native/issues/1167#issuecomment-144077138

But how can I have in the new android structure?

public class MainActivity extends ReactActivity {
    /**
     * Returns the name of the main component registered from JavaScript.
     * This is used to schedule rendering of the component.
     */
    @Override
    protected String getMainComponentName() {
        return "App";
    }

    /**
     * Returns whether dev mode should be enabled.
     * This enables e.g. the dev menu.
     */
    @Override
    protected boolean getUseDeveloperSupport() {
        return BuildConfig.DEBUG;
    }

    /**
     * A list of packages used by the app. If the app uses additional views
     * or modules besides the default ones, add more packages here.
     */
    @Override
    protected List<ReactPackage> getPackages() {
        return Arrays.<ReactPackage>asList(
            new MainReactPackage(),
            new VectorIconsPackage(),
        );
    }
}

cc @satya164

Hey @sibeliusseraphini have you tried this?

https://github.com/facebook/react-native/issues/1167#issuecomment-141730183

@PierBover I don't wanna to replace the default fonts of android, I wanna use a custom one

@sibeliusseraphini https://medium.com/@gattermeier/custom-fonts-in-react-native-for-android-b8a331a7d2a7#.njou2fo8b

@sibeliusseraphini And this answer on SO should help as well: http://stackoverflow.com/a/37413939

@corymsmith in the Medium article it says:

Make sure the fonts are lowercase only and follow this pattern: fontname.ttf, fontname_bold.ttf, fontname_light.ttf, fontname_bold_italic.ttf

But in the SO answer:

The name of the file has to match the fontFamily exactly. For instance, if fontFamily is 'Source Sans Pro', the file must be called Source Sans Pro.ttf (and NOT SourceSansPro.ttf). Any suffixes as mentioned in the following paragraph are automatically removed from the file.

Is there any definitive source on how these file must be named?

@PierBover From my understanding the font name needs to match the file name exactly. Not sure it matters whether its lower case or not, try both and see if one doesn't work :)

@corymsmith Ok... I'll try that. :)

Anyone knows how does the font weight work?

From the SO answer and Medium article it seems you can say myfont_light_italic.tff but how do you specify light in the styles?

The Text component docs say this:

fontWeight enum('normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900')

If it's like CSS 300 should correspond to _light in the .ttf file name.

What about the other weights? Do we name files like myfont_200.ttf or myfont_900.ttf?

@PierBover

If you have a peek at this:
https://github.com/facebook/react-native/blob/235b16d93287061a09c4624e612b5dc4f960ce47/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactFontManager.java#L21

For each font family the bold, italic and bold_italic variants are supported. Given a "family" font family the files in the assets/fonts folder need to be family.ttf(.otf) family_bold.ttf(.otf) family_italic.ttf(.otf) and family_bold_italic.ttf(.otf).

So if you need other weights then it would seem like you should include the different font file for that weight and then name the file / use the font name that matches the file name for that weight.

So in the styles I'd use:

fontFamily: ‘myfont_light_italic’

?

I guess that should work.

If I have time I will try to fix this so that you can also specify the weight in the .ttf file like myfont_300_italic.ttf. This makes more sense than using classic names like light,black, etc. Plus, @ericvicenti said here they want to support CSS like font weights instead.

@PierBover thanks for all this links, I hope one of them works

Here is how i get custom font working in four step:
1- Copy TTF file to /projectdir/android/app/src/main/assets/fonts ( thanks to: https://github.com/facebook/react-native/issues/1167#issuecomment-161232815 )
2- Delete these folders: projectfolder/android/.gradle + projectfolder/android/app/build ( thanks to: https://github.com/facebook/react-native/issues/1167#issuecomment-161250593 )
3- Apply fontFamily to elements ( if your ttf file is yekan.ttf, your font family should be: fontFamily: 'yekan' )
4- react-native run-android

@tje3d so you didn't have to write any Java code for this?

@kunal95 yes

@tje3d It worked! 😀 Thanks

I used rnpm to fix this. It basically does what @tje3d described.

Im specifying this in my package.json file

"rnpm": {
    "assets": ["Fonts"]
}

I've placed my fonts in the _Fonts_ directory and then just run rnpm link

Thanks @krokofant for your method!

I'm going to describe a bit what happens for the rest.

First it copies the fonts correctly for Android:

image

They also appear in Xcode in the Resources folder

image

Finally you use them like this in your StyleSheet:

fontFamily: 'opensans',
fontWeight:'bold'

Success

image

From looking at the code https://github.com/facebook/react-native/blob/0.34-stable/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactFontManager.java

It doesn't look like react native supports light variants of fonts yet. If I get time I may add a PR for support

Anyone know how to detect when the fonts are fully loaded? I noticed (at least in iOS simulator) that the font changes don't take effect for a few hundred milliseconds.

@JulianKingman u can use this https://gist.github.com/sibelius/e1db241ab225aba2adb84dbd8ae6525b to check if the font name was loaded

@sibelius so then would you recommend just having a setTimeout that refreshes every 10ms or so to check again, in order to update the component?

I think all the fonts are loaded when react starts

everytime u change the font u need to recompile the native code

As @tje3d said before, I made those 4 steps and also I ran:
cd android
gradlew clean

One thing more: my font file is called "Lato-Bold.ttf" so I had to use {fontFamily: 'Lato-Bold'} to make it works instead of {fontFamily: 'lato-bold'} as I read in some pages. So I had to use the fontFamily as it called.
Thank @tje3d !

I'm having some issues getting custom fonts working on Android (however, it works fine on iOS).

  • I've installed my fonts in ./android/app/src/main/assets/fonts:

screen shot 2017-02-25 at 6 39 35 pm

  • My project uses an abstract CustomText wrapper component, to ensure the custom font is applied everywhere. When applying the fontFamily, I follow the <filename>.ttf pattern mentioned by folks above. E.g., since my font file is named opensans.ttf, my fontFamily is opensans for the Android platform.

screen shot 2017-02-25 at 6 40 56 pm

  • I ran this (from root of react native project, to clear cached android stuff):
rm -rf ./android/.gradle
rm -rf ./android/app/build
cd android && ./gradlew clean && cd ..

Then ran:

react-native run-android

However, my fonts still don't line up. I have it custom fonts functional on iOS, and you can see the comparison here:

screen shot 2017-02-25 at 6 43 24 pm

Any ideas as to what could be going wrong? I made sure I killed the packager before deleting the cached android files and re-starting the android simulator.

Same issue as @petermikitsh.

React Native v 0.35
Font I'm trying to load is Gotham Ultra.ttf. I renamed to gotham_ultra.ttf and moved to ./android/app/src/main/assets/fonts

I tried deleting the .gradle folder and re-running the packager and react-native run-android.

I've tried every suggestion on this issue but nothing appears to work.

If it helps, I'm using a fork of https://github.com/start-react/native-starter-kit

Mine works now! I was adding the style to a single Input component, expecting the placeholder text to have the new font. However, it did not affect the placeholder text but did affect the actual typed text.

From https://blog.bam.tech/developper-news/add-a-custom-font-to-your-react-native-app

4 - Format the Android font files

In the android/app/src/main/assets/fonts folder where your font was copied, rename the files so that:

  • the prefix matches your .ttf files names
  • the suffix is snake_case

In my case:

Intelligent Design - Averta-Bold.otf had to be renamed to Averta_bold.otf (along with 15 other variations).

In my case in Android it worked after setting fontWight: '400' . fontWeight: 'bold' caused fallback to System font.

I'm getting it working after removing fontWeight! Apparently, I have only 400 weight font.

Is there a way that android can provide a list of available fonts and its font name?

I was using OTF file font and having errors like font not found, for the fontFamily i was mistaken to use the Full name attribute at the font book, the correct one was PostScript name

I don't understand why iOS uses FONTNAME-some instead of FONT-NAME-some whether the file is FONT-NAME-some.ttf

I've implemented a function in order to use fonts on both platforms.

// utils.js

import { Platform } from 'react-native'

/**
 * Add fonts compatibility across iOS & Android.
 *
 * Examples:
 * + SF-UI-Display-Medium.ttf will:
 *    Android: SF-UI-Display-Medium
 *    iOS: SFUIDisplay-Medium
 * + Roboto-Medium.ttf will:
 *    Android: Roboto-Medium
 *    iOS: Roboto-Medium
 */
export default fontCompat = (fontFamily) => {

  if (Platform.OS === 'ios') {
    return fontFamily.replace(/(.*)-/, (x) => x.replace(/-/g,'')+'-');
  }

  return fontFamily;
}
import { fontCompat } from './utils.js'

const myStyles = {
   one: {
       fontFamily: fontCompat('SF-UI-Display-Medium')
   },
   two: {
       fontFamily: fontCompat('Roboto-Medium')
   },
}

@brunobar79 I think because it uses the font's name, not the font's filename (PostScript name, as @a3diti pointed out)

(@JulianKingman I think you wanted to reply to @brunocascio instead)

@JulianKingman I got it. Good catch, thanks!

Was this page helpful?
0 / 5 - 0 ratings