NativeScript Core

Icon Fonts

While bitmap images are great, they present challenges in designing mobile applications. Images increase the size of the application if they are embedded in it. If not, they require additional http requests to be fetched. Images consume memory. Furthermore, bitmap images do not scale well. If scaled up, they lose quality. If scaled down, they waste space. On the other hand, fonts scale well, do not require additional http requests for each glyph and do not increase memory usage significantly. Icon fonts contain icons instead of alphabet characters and can be used instead of images in mobile applications.

Using Icon Fonts in NativeScript

  1. Choose or generate an icon font that best matches your needs. Two popular icon fonts are IcoMoon and Font Awesome.
  2. Once you have downloaded the icon font to your machine, locate the TrueType font file with extension .ttf.
  3. In your root application folder (This is the app folder for NativeScript Core, and the src folder for Angular 6+), create a folder called fonts and place the .ttf there.
  4. Follow the instructions on the icon font webpage to determine the hex codes of each font glyph, i.e., icon. Add a Label component to your NativeScript app and bind the Label's text property to a one-letter string generated from the character code of the icon you want to show, i.e., String.fromCharCode(0xe903).

Note: While this documentation article is focused on icon fonts, the above workflow is a hundred percent applicable for both text fonts and icon fonts (except that with text fonts step 4 as they don't include icons but only plain text).

Platform Specific Font Recognition

There is a conceptual difference in how .ttf fonts are recognized on iOS and Android. On Android, the font is recognized by its file name while on iOS it is recognized by its font name. This means that fonts that are created with a font name which is different from the file name has to be registered with both names in your CSS rule.

.fa-brands {
    font-family: "Font Awesome 5 Brands", "fa-brands-400";
}

In the above example, the fa-brands-400.ttf (as downloaded from the FontAwesome site) has a font name Font Awesome 5 Brands. With the above CSS, the font is recognized on both iOS (by the font name Font Awesome 5 Brands) and Android (by the file name fa-brands-400).

Note: There are specific scenarios where the creators of the fonts might have released two differently named ttf files but with the same font name (see the example below).

file name font name
fa-solid-900.ttf Font Awesome 5 Free
fa-regular-400.ttf Font Awesome 5 Free

Notice that in the above example the file names are different, but the registered font name is the same (use the Font Book application on Mac or the Control Panel Fonts section on Windows to see the actual font name). While this is no issue on Android, it renders the second font unusable on iOS. To handle similar cases additional CSS font properties, such as for example font-weight, must be added.

/* 
    File name: fa-regular-400.ttf 
    Font name: Font Awesome 5 Free
*/
.far {
    font-family: "Font Awesome 5 Free", "fa-regular-400";
    font-weight: 400;
}

/* 
    File name: fa-solid-900.ttf 
    Font name: Font Awesome 5 Free
*/
.fas {
    font-family: "Font Awesome 5 Free", "fa-solid-900";
    font-weight: 900;
}

Usage

The example demonstrates, how to use setup the font-family property via CSS and how to define the needed icons via XML.

<!-- Using fa-regular-400.ttf -->
<Label text="&#xf019;" class="far"></Label>

<!-- Using fa-brands-400.ttf -->
<Label text="&#xf39e;" class="fab"></Label>

<!-- Using fa-solid-900.ttf with FormattedString -->
<Label class="fas" textWrap="true">
    <FormattedString>
        <Span text="&#xf053;" fontAttributes="Bold"></Span>
    </FormattedString>
</Label>

<!-- Using IcoMoon-Free.ttf -->
<Label text="&#xe904;" class="ico"/>
.far {
    font-family: "Font Awesome 5 Free", "fa-regular-400";
}

.fab {
    font-family: "Font Awesome 5 Brands", "fa-brands-400";
}

.fas {
    font-family: "Font Awesome 5 Free", "fa-solid-900";
}

.ico {
    font-family: "IcoMoon-Free";
}

WIth NativeScript 6 and above, we can use icon fonts with Image elements. For that purpose the font:// prefix is needed to set the icon font code.

<!-- 
    In case, when the stretch property is set to aspectFit or aspectFill
    the font-sizde will be disreagarderd and the image will take the vailable space
    assigned through width/height or through its parent size

    Setting the stretch property to none will allow using the font-size property
-->
<Image src="font://&#xf51e;" stretch="none" class="fas"></Image>
.far {
    font-family: "Font Awesome 5 Free", "fa-regular-400";
}

.fab {
    font-family: "Font Awesome 5 Brands", "fa-brands-400";
}

.fas {
    font-family: "Font Awesome 5 Free", "fa-solid-900";
}

.ico {
    font-family: "IcoMoon-Free";
}

Note: Images have specific stretch options (none, aspectFit, aspectFill). At the same time the icon fonts are having font-size which can control the size of our font. If you want to set the size of your icon through the font-size property then set stretch property to none. Any other values of the stretch property (including the default one) will cause the icon to be streched by measuring the image (or if there is no sizes set, the parent layout in whcih the image is nested).

Improve this document

Demo Source


Tips And Tricks

The example shows, how to use setup the font-family property via CSS and how to define the needed icons via Code-Behind.

<ListView items="{{ glyphs }}">
    <ListView.itemTemplate>
        <StackLayout orientation="horizontal" horizontalAlignment="center">
            <Label text="{{ icon }}" class="ico"/><!-- the icon (glyph) -->
            <Label text="{{ code }}" /><!-- the icon code -->
        </StackLayout>
    </ListView.itemTemplate>
</ListView>
const Observable = require("tns-core-modules/data/observable").Observable;
function pageLoaded(args) {
    const page = args.object;
    const viewModel = new Observable();

    const glyphs = [];
    for (let charCode = 0xe903; charCode <= 0xeaea; charCode++) {
        const glyph = new Observable();
        glyph.set("icon", String.fromCharCode(charCode));
        glyph.set("code", charCode.toString(16));
        glyphs.push(glyph);
    }
    viewModel.set("glyphs", glyphs);

    page.bindingContext = viewModel;
}
exports.pageLoaded = pageLoaded;
import { Observable, EventData } from "tns-core-modules/data/observable";
import { Page } from "tns-core-modules/ui/page";

export function pageLoaded(args: EventData) {
    const page = <Page>args.object;
    const viewModel = new Observable();

    let glyphs = new Array<Observable>();
    for (let charCode = 0xe903; charCode <= 0xeaea; charCode++) {
        const glyph = new Observable();
        glyph.set("icon", String.fromCharCode(charCode));
        glyph.set("code", charCode.toString(16));
        glyphs.push(glyph);
    }
    viewModel.set("glyphs", glyphs);

    page.bindingContext = viewModel;
}
/*
  File name: IcoMoon-Free.ttf
  Font name: IcoMoon-Free
*/
.ico {
    font-family: 'IcoMoon-Free';
    font-size: 48;
}

 /* only for reference, is NOT working in this example (due to wrong glyph codes) 
 .fa {
    font-family: "Font Awesome 5 Free", "fa-regular-400";
    font-size: 48;
 }
 */

Improve this document

Demo Source