Developing A Custom Icon Font For FlutterFlow

Nora Warschewski
NanoGiants
Published in
14 min readApr 11, 2024

You’re tasked with revamping an app using FlutterFlow, aiming to provide users with a seamless journey from start to end. You understand that icons play a significant role in guiding users through the app’s myriad features, how they affect accessibility and usability, and their importance for the brand. But wait, what? FlutterFlow requires an icon font? Where and how do you begin?

In this article, I’ll share my experience developing an icon font tailored for a FlutterFlow app highlighting best practices for developing an icon font and practical insights gained along the way. As I’m not only a UI/UX designer but also a type designer, I was thrilled to be invited to support the team with my expertise on this project.

Corporate illustration of two people giving each other a high five. One is carrying a symbolic logo of FlutterFlow. The other one a stylised “pen tool”

Understanding The Need For An Icon (Font)

Icons play an important role in app design by serving as visual cues that enhance usability and navigation, providing visual landmarks, guiding users through complex interfaces and ensuring coherence throughout different contexts. Icons transcend language barriers and support diverse user demographics by instantly communicating meaning; for instance, a magnifying glass icon universally signifies search functionality. Incorporating icons alongside text labels or independently improves overall usability, enabling users to identify functions quickly and reducing cognitive load.

Utilizing an icon font offers numerous advantages in the context of UI design. Firstly, an icon font provides an easy way to scale shapes and strokes alongside the cap height of text or to adjust the weight through variable font technology. Further, an icon font simplifies maintenance and updates, as designers can quickly add new icons or modify existing ones by updating the font file and developers can update said font file with the subsequent version. Additionally, it can be used by other teams such as branding and marketing without dealing with individual assets.

What’s The Deal With FlutterFlow?

Low-code represents a visual method for software development, facilitating the rapid delivery of applications with minimal manual coding. Utilizing a low-code platform’s graphical user interface and drag-and-drop functionalities automates various development tasks, reducing reliance on conventional programming methods. This approach democratizes app development, empowering “citizen” developers — such as business analysts or project managers — with limited coding expertise, to participate more effectively in the development process [1].

FlutterFlow is a no-code platform enabling users to develop iOS and Android apps effortlessly. With Google’s Firebase integration, developers can handle user authentication, define data types within the platform’s editor, and incorporate widgets seamlessly.

One of these widgets is the icon widget: FlutterFlow has Material Design and Font Awesome icons already integrated, set up, and ready to use. However, a lot of projects require custom icons, right? To do so, you need a TrueType font (.ttf) and a .dart file referencing the respective Unicode code points. What?!

Going From Single SVGs To One Compiled Font

In the following, I outline the steps the team and I undertook to design and iterate the icon font for a FlutterFlow app.

1. Collecting All Icons Needed And Documenting Unicode Values

Collaboration with the UI designer was key in this initial phase. Using Figma, my teammate (🫶) meticulously documented the icons, and the associated Unicode values, and built Figma components to be used in the UI. For a straightforward process, several tools and websites help you find the correct Unicode value [3, 4, 5].

I then exported individual SVG files from Figma in preparation for the icon font. At a later stage, when we had the first version of the icon font ready, we replaced the SVG files in the components with the icon font for seamless updates.

2. Choosing A Font Editor

Leveraging my practical knowledge in GlyphsApp [6], I opted for this font editor, although acknowledging other options, such as FontForge [7] or RoboFont [8]. Glyphs provided a familiar and efficient platform for type design, facilitating a smooth workflow throughout the design process.

While researching how FlutterFlow integrates icon fonts, I looked into generators such as fluttericon.com [9] or icomoon.io [10]. However, upon opening the generated font files, I learnt that these are not mapped onto Unicode, the font engineering is a bit of a mystery, and there’s a big limitation in quality assurance. However, it seems like those fonts work well in FlutterFlow anyway. Personally, I doubt that the speedy process of generators outweighs the quality and control provided by designing a custom typeface with professional software but it is an option.

3. Setting Up The Metrics

One point in vector-drawing software like Adobe Illustrator equates to one unit in Glyphs. The average cap height corresponds to about 70 % of the UPM (units per em) size and given that the default UPM is set to 1000 units, resulting in the average cap height being around 700 units [11]. Since we aimed for our icons to be the size of a capital letter in the typeface used for the UI, I set up the metrics accordingly. However, understanding the requirements and peculiarities of FlutterFlow, we had to go back and forth to configure the metrics within the font editor to avoid any issues of misaligned icons. Eventually, we determined that a monospaced font with 1024 units offered optimal consistency, aligning with the framework.

Horizontal and vertical metrics systemise the project.

Ideally, to avoid rounding errors and uneven weights, the icons are already scaled to the correct size before being copied to the font editor or the icons are directly designed in the font editor (even better). In our case, the icons were designed on a 44px * 44px grid before being copied to the font editor and since the metrics and engineering were a work in progress, we had to scale the whole character set again in Glyphs. It worked out well but we will iron out this small bump in our workflow in the next project.

4. Setting Up Unicode Characters

Utilizing the Unicode values documented by the team in Figma, I mapped each icon onto its respective Unicode value [12]. Often, icons are not entirely new characters, which denote the meanings behind those visual representations.

“[A character is] the smallest component of written language that has semantic value; refers to the abstract meaning and/or shape, rather than a specific shape” unicode.org [13]

Instead, they often reinterpret existing icons. In essence, characters are what you input, while glyphs are what you perceive through the interface. The assigned Unicode value establishes the relationship between the character and the glyph [12].

Screenshot from the font view in Glyphs displaying the greyed-out icon (the glyph is empty), the production name, and the Unicode value.

Categorizing icons into punctuation, symbols, and ‘private use’ ensured clarity, accessibility, and maintainability throughout the project’s life cycle. Most icons in our font can be categorized as symbols and/or emojis and hence they already come with their specified Unicode code point, but where do we put fully custom solutions?

The answer is simple: we allocate them to new glyphs linked with reserved Unicode values in the Private Use Area (PUA) [14]. While Unicode covers a broad range of symbols, a handful of code points are set aside in the PUA for whatever purpose. This can include icons for social media, special icons associated with the brand or even logos. Ultimately, these are reserved for personal or specialized use, as designated by the Unicode Consortium [15].

Screenshot of the ‘Private Use Area’ in Glyphs.

Assigning icons to a random code point, for example, adding a panda emoji to U+004E LATIN CAPITAL LETTER N can potentially confuse screen readers. Some screenreaders skip Unicode characters entirely or read out something irrelevant to users trying to comprehend the displayed content. Hence, it is important to label the icons correctly with a semantic name relevant to the action the icon is supposed to support. If, for any reason, the icon font fails to load and is replaced with a fallback font, the displayed icon should match at least in meaning [13].

5. Drawing Good Paths

Precision was significant in creating clean paths for the icons. Attention to detail, such as node position and closure of open contours, ensured seamless integration and functionality within the font file. Additionally, implementing optical corrections and maintaining curve tension enhanced visual clarity and legibility [16].

PSA: Drawing clean paths is not exclusive to type design. It should be a standard practice for illustrations and other digital designs as well.

While working on the project, I realised that there is a need for double-checking and cleaning up the paths in Figma before pushing them onto the UI to achieve great results and cleaner code. The files exported from Figma were surprisingly messy on the inside even though they looked good on the outside.

For balanced curves, the nodes and handles should look like a sad frog. 🐸

To better understand what a “good path” is and what problems a font generator might encounter, we take a small detour and briefly look into some important aspects of drawing clean icons for fonts.

Node Positioning
It is essential to position nodes at the horizontal and vertical extremes of each outline. Ideally, handles extending from the nodes should be orthogonal, aligning horizontally or vertically. This guideline remains crucial not only when drawing consecutive curves, such as in a circular icon, but also during the transition from straight lines to curves [17].

With Figma or other vector-drawing software, the paths may be set up correctly but once you edit and rotate the shape, it alters the node positioning in an unwanted and not immediately visible way.

Nodes should be placed on the extremes with the handles extending orthogonal in a horizontal or vertical direction. This placement further allows for great control over the tension of the curve.

Number Of Nodes
You’ll always want to keep your paths nice and clean and therefore reduce the amount of nodes used to create a path. It has practical reasons: you have better control, it ensures smooth curves and transitions, it reduces the file size, and enables you to design for interpolation.

The number of nodes should be reduced to the amount necessary to draw clean outlines.

Closed Contours
Contours or paths need to be closed; otherwise, they won’t function correctly when you attempt to compile the font file. Unlike in other vector-drawing software, exported fonts cannot apply strokes to open outlines, so a contour must be closed for a shape to appear solid [18].

The open path does not render as a solid shape and it would throw an error in the export.

Path Direction
An arrowhead marks the starting point of a closed path, indicating the path direction. Outer paths must follow a counterclockwise direction, whereas enclosed paths, like the inner path of an “O” or an outlined circle, should proceed clockwise. Therefore, the path direction needs to be corrected if necessary.

If the icon system is aiming for interpolation (not supported in FlutterFlow), it’s essential to ensure that the path direction, starting points, and shape order remain compatible and consistent across all masters [19].

The triangles indicate the path direction. They should point in opposite directions for a shape to appear solid.

Optical Corrections
Icon systems and icon fonts in particular can derive significant benefits from the best practices established in type design, notably in how optical corrections are managed when designing letters. These principles can be transferred to icon systems and the creation of an icon font. Just as in type design, where consideration is given to optical corrections to ensure optimal legibility and visual harmony, similar attention to detail is essential in crafting icons within an icon font. By leveraging the techniques and methodologies refined in type design, designers can effectively apply optical corrections to icons, resulting in improved clarity, consistency, and aesthetic appeal [20].

Consider adding an overshoot for shapes to appear optically the same size.

Another common mistake in icon design (or even UI and graphic design) is treating the weight of horizontal and vertical elements equally. While it makes sense to give them the same thickness, it optically doesn’t. Our brain gets tricked into thinking they have different weights even though they are the same in terms of numbers. Similarly, diagonals crossing each other like an xmark can appear ‘broken’ and need to be adjusted so that the bars get perceived as continuous lines.

Remember, you’re designing for the eye, not the grid.

Bonus

Corner Components
If the design phase is still underway and you don’t want to flatten any outlines or determine e.g. a specific radius yet, corner components are for you. Corner components enable you to edit the icon system across the whole character set later on. Going from rounded corners to straight corners in 293 icons across several styles? No problem.

Corner components to the rescue. 😻

Interpolating Styles
In the project we were working on, I set up two styles for filled icons and outlined icons. Depending on the project and type of client, icons can be set up for interpolation. It enables you to easily export your icon system in different weights or animate them. This would also imply that you would need to keep the shape order in mind and you would need to adhere to everything mentioned above regarding the amount and type of nodes or the path direction.

6. Generating The .dart File

FlutterFlow also requires a .dart file to go along with the font. The file depicts the class and Unicode code points for each character. To facilitate the process and to keep the font and code maintainable, I wrote a Python macro for Glyphs which generates the .dart file from the selected layer (in our case, the layers refer to the two font styles filled and outline) and selected characters. The main advantage was the ability to update the .dart file whenever changes occurred and to avoid any errors that would occur by writing it manually. Hence, it was important that the characters were connected to their respective Unicode value and had a production name.

Work smarter, not harder. Investing a little bit of time beforehand into the macro was a perfect choice for this project and helped with a smooth workflow later on. Automate where you can.

7. Exporting The Font File

In principle, exporting your font via File > Export should suffice to get you up and running. However, there’s a crucial obstacle when it comes to testing an unfinished font: font caches. Familiarize yourself with how fonts are cached and how you can avoid caching issues [21]. Ultimately, the choice is yours, but consider yourself warned.

Learning: Granted, I was sloppy with versioning my source files and the exported font files 🌚. Usually, I’d version the source files through GitHub and do versioning directly in the .ttf files based on best practices for font development [22, 23]. While it didn’t cause me any problems in this project (I think), it generally helps to mitigate problems and risks. I’ll do better, I promise.

8. Importing The Font To FlutterFlow

Adding custom icons to your app to your app in FlutterFlow requires you to upload a .ttf and .dart file [24]. To incorporate the icon into the app project, the icon widget needs to be simply dragged from the base elements tab, or alternatively, added directly from the widget tree [25].

Learning: We only tested the custom icons in FlutterFlow after the first few versions. While the icons looked aligned as expected in Figma, the icons weren’t aligned and overflowing the frame in FlutterFlow. This can be avoided by importing and testing early on.

An exemplary screenshot of a misaligned and overflowing icon in FlutterFlow.

What Have I Learned Throughout The Project?

Bad Paths 🤝 Figma
During the process, I encountered a few unexpected challenges when working with SVG paths exported from Figma. These paths often contained quadratic curves, superfluous and random off-path nodes, paths on top of each other, and unbalanced handles, which required a lot of modification in the font editor.

Left: Figma logo built in Figma / Right: Imported SVG from Figma to GlyphsApp

In the example above, you can see that the SVG imported to Glyphs doesn’t use the correct type of nodes (corner vs. round), it contains redundant nodes, the path direction is not set up correctly, and shapes don’t sufficiently overlap.

This circumstance can also become critical when working with clients or other third parties supplying SVG files since it would imply a serious clean-up lane for these icons.

Test Early Or Be Doomed To Fix Later 🫠
Moreover, I’ve been reminded again of the importance of testing fonts early on and throughout the whole design phase to ensure they work and align as desired, saving time and effort in the long run. In type design, it is a standard practice to create proofing documents and printouts and this project has shown that we’d need a similar workflow for ‘proofing’ the icon font in FlutterFlow to ensure its quality.

FlutterFlow 💔 Font Technology
While I got super excited to implement some font technology, I’ve also learned from the team that the current method can be quite time-consuming when moving from FlutterFlow to a Flutter project as many changes would still need to happen in FlutterFlow.

While an icon font is required for the workflow, FlutterFlow ignores some integral functionality of typefaces such as setting correct metrics or connecting styles within a type family. Thoughts?

Teamwork Makes The Dream Work 💖
Lastly, I always appreciate the power of teamwork. Collaborating closely with interface designers and developers ensures visual integrity, technical feasibility, and promotes seamless integration. Reviews with the team contributed to the iterative refinement of the font, incorporating valuable insights from our disciplines and informed feedback ultimately enhancing the workflow for the whole team. It’s truly a case of “teamwork makes the dream work” as we all contributed and leveraged our specialized skills. I still feel very lucky to have been part of this project and working with an amazing team.

The Future Of Icon Fonts Is Bright

The future outlook for icon fonts, beyond FlutterFlow, is promising, with various opportunities for innovation and enhancement.

I’m looking forward to

  • leveraging font technology for colourizing and animating icons providing a dynamic experience and driving user engagement,
  • employing variable icon fonts to seamlessly match the stroke weight of the icons to the textface or other UI elements ensuring visual consistency and enhancing brand recognition,
  • integrating subtle micro interactions on the icons presents exciting opportunities for improving the interaction design and creating enjoyable user experiences,
  • and unlocking the power of COLRv1 [26] fonts in mobile apps one day in the hopefully not-so-far future.

In closing, I invite you to share your experiences and insights. Whether you’ve encountered success stories, had the same issues, or stumbled upon better solutions for FlutterFlow, I’m curious about your learnings. Feel free to reach out to me on LinkedIn: Nora Warschewski! Thanks for reading!

NanoGiants corporate illustrations on a dark blue background. The text reads “NanoGiants—Choose to Grow”. Below a call-to-action reads “Follow us on Medium”

List Of Resources

--

--

Nora Warschewski
NanoGiants
0 Followers
Writer for

Designer, Type Enthusiast, Creative Coder