An Introduction to OpenType Substitution Features

The Type1 format where 256 characters are assigned to keys on our keyboard, is becoming a thing of the past. We now design and produce OpenType fonts which can consist of thousands of characters — additional ligatures, various figure sets, small caps, stylistic alternates, … — referred to as glyphs. With these many sets of glyphs integrated in a single font, we are faced with the challenge of including definitions instructing the applications we're using when to show which glyph. Simply adding a glyph with a ligature to your font doesn’t mean the program you’re using knows when or how to apply it. Whether you want your typeface to change the sequence of f|f|i into the appropriate ligature or want to use old-style figures instead of tabular, you’ll need to add features to your font — glyph substitution definitions — to make it happen.

In this article we’ll give you a look behind the scenes of OpenType substitution features — a general rather than comprehensive overview as the subject is simply too vast. We’ll start casually and work our way to more complex features and ideas. All examples that we will discuss should be considered starting points, just to pique your interest. Read on and find out that it’s really not difficult!

What does a feature look like?

Let’s take a look at a simple example that, like all OpenType features we’re talking about here, deals with the replacement of glyphs, called glyph substitution (short GSUB). It always comes down to the same thing: substitute a single glyph or a sequence of glyphs by another glyph.

liga_glyphs.gif Assuming you have your glyphs in question already drawn (f, i and the ligature glyphs called f_i and f_f_i), all you need to do is add some code to control the substitution, like this:

	feature liga { # I'm just a comment
		sub f f i by f_f_i;
		sub f i by f_i;
	} liga;

feature followed by liga, and repeated in the last line is the predefined name of the feature, the identifier that a program like QuarkXPress or InDesign needs in order to know which feature to look at when you choose «Ligatures», (see below for a comprehensive list of feature names and the features they trigger.) The sub statements — you can also write substitute — within the curly brackets tell the program that if the sequence of glyphs named f|f|i or f|i is found (in the feature statement the glyphs of a sequences are separated by a space), replace it by the glyphs named f_f_i resp. f_i. Lastly, after every statement as well as at the end of the feature, place a semicolon.

To see what happens look at the following comparison of input and output, (to tell the different glyphs in a sequences apart I’ve used a divider: |)

Input: R|e|f|i|n|i|n|g|space|a|f|f|i|n|i|t|y|question


Output: R|e|f_i|n|i|n|g|space|a|f_f_i|n|i|t|y|question


What Do I Need to Create a Font with Features?

You need a font program that supports feature definitions such as FontLab Studio, DTL’s FontMaster, or FontForge, to name the most common. These allow you to freely define glyphs/glyph names as well as offer integrated feature editors. In FontLab Studio your work space would look something like this:


Top left: the font window with your glyphs.
Top right: the Classes panel, shows the names of all your classes (left), their content (bottom right) and a visual representation (top right).
Bottom left: the OpenType panel, shows the names of your features (left), feature definitions (top right), and classes (bottom right).
Bottom right: the Preview panel in which you can test your features, shows a comparison of your input (top) and output (bottom). Depending on which features you choose to activate (left), your output will change.

What are features used for?

In many of the newer fonts, you’ll find various figure sets (old style, lining, super and subscript figures, …) which need to be controlled or small caps as well as alternative character shapes and fractions. A favorite of many are or course, ligatures.

Choose from the following list of features to see some typical applications. Compare the results to the input and take a look at the exemplary feature code which is explained in detail further down:

Input: All featues switched off


Output: Ligatures (liga) switched on

	feature liga { # Ligatures
		sub f i by f_i;
	} liga;

Output: Stylistic Alternates (salt) switched on

	feature salt { # Stylistic Alternates
		sub [a g] by [a.salt g.salt];
	} salt;

Output: Stylistic Set 04 (ss04) switched on

	feature ss04 { # Stylistic Set 04
		sub parenleft three by three.cameostart;
		sub period by period.negative;
		sub two parenright by two.cameoend;
	} ss04;

Output: Small Caps (smcp) switched on

	feature smcp { # Small Caps
		sub @lowercase by @smallcaps;
	} smcp;

Output: Superscript (sups) switched on

	feature sups { # Superscript
		sub @figures_standard by @figures_sups;
		sub @punctuation_regular by @punctuation_sups;
	} sups;

Output: Fractions (frac) switched on

	feature frac { # Fractions
		sub slash by fraction;
		sub @figures_standard by @figures_numerator;
		sub fraction @figures_numerator' by @figures_denominator; 
		sub @figures_denominator @figures_numerator' by @figures_denominator;
	} frac;

Output: Lining Figures (lnum) switched on

	feature lnum { # Lining Figures
		sub @figures_standard by @figures_lining;
	} lnum;

What rules do I need to follow?

Naming your glyphs

A must for every well functioning typeface is properly named glyphs. Your letter Ä would use the descriptive glyph name Adieresis, and its Unicode value 00C4. If you supply the correct glyph name (for example iacute) your font program usually knows what the Unicode for a glyph should be (00ED). If you or your font program are at a loss, try Adobe’s glyph list for new fonts (AGLFN) which lists more than 600 glyph names and their matching Unicode values.

Glyphs that should only have a glyph name (and no Unicode value!) are variants, which are the ones we usually access with the help of features — like a.swsh or g.salt. Since they are accessed via their base glyph (a with its Unicode 0061 is the base glyph of a.swsh) only a glyph name is needed. The names of the variant glyphs are often assembled like this: source glyph’s name plus the feature’s abbreviation, separated by a dot: a.swsh as the swash variant of a.

Naming your features

All features have predefined four letter names. Ligatures for example is called liga, the Stylistic Alternates feature is named salt, and Stylistic Set 04 ss04. Make sure that the application activates the desired features by using the appropriate name. Examples of the the most common feature names you’ll find below in our section Which features is activated by which menu item?

Feature statement schemes

For the definition of features, you work with a flexible but straight-forward syntax. Design programs currently support replacements according to the following schemes:

  1. Substitute a glyph by another glyph
  2. Substitute a sequence of glyphs by a certain glyph
  3. Substitute glyph from a list by certain glyph / glyph in a list
  4. Substitute glyph from a referenced list called class, by certain glyph / glyph from a referenced class

1st scheme

The following Stylistic Alternates feature named salt, handles the substitution of the standard versions of a and g with the alternative versions of those glyphs. These variants could be named a.salt and g.salt, for example.

	feature salt { # my Stylistic Alternates
		sub a by a.salt;
		sub g by g.salt;
	} salt;

2nd scheme

Our ligatures feature, same as above.

	feature liga { # my Ligatures
		sub f f i by f_f_i;
		sub f i by f_i;
	} liga;

3rd scheme

Like the example of the 1st scheme, the glyph a is replaced by a.salt, and g by g.salt, but the feature syntax allows us to be more efficient as the following example shows. Here each glyph of the first list is replaced by the corresponding glyph of the second.

Input: D|o|n|quoteright|t|space|e|a|t|space|m|y|B|a|g|e|l|exclam|exclam|exclam


Output: D|o|n|quoteright|t|space|e|a.salt|t|space|m|y|B|a.salt|g.salt|e|l|exclam|exclam|exclam

	feature salt { # my Stylistic Alternates, compact using listst
		sub [a g] by [a.salt g.salt];
	} salt;

4th scheme

Up until now we’ve only dealt with four glyphs, but let’s see how you can keep the overview when you need to control a substantially larger number of glyphs, like small caps for example. Here we don’t list our glyphs within the feature itself, but instead refer to lists that contains all the glyphs we need. These lists are called classes and are either created in the Classes panel or directly in the lower right-hand field of the OpenType panel.


In FontLab you can define classes, lists of glyphs, in two locations: either in the Classes panel or directly in the bottom right space in the OpenType panel. The advantage of defining classes in the Classes panel is that you have a visual representation of the glyphs in your list. If you choose to define your classes in the OpenType panel you’ll find that you can add and adjust classes more quickly.

The lists in the Classes panel handle each list as a separate item (see the Classes panel in the above image):

This is what the lists looks like if you choose to write them in the OpenType features panel (see the OpenType panel in the above image, lower right-hand field):

@lowercase = [a b c d e f g h i j k l m n o p q r s t u v x y z];
@small_caps = [];

So instead of writing our glyphs directly into the feature we refer to classes, marked by @. The position of the resp. glyphs in these classes must of course correspond, just like they do in our Stylistic Alternates feature.

	feature smcp { # my Small Caps feature
		sub @lowercase by @small_caps;
	} smcp;

Input: I|space|L|o|v|e|space|T|y|p|o|g|r|a|p|h|y|exclam


Output: I|space|L||||space|T||||||||||exclam


Substitute — depending on the context!

In the previous examples, the substitution of a glyph took place when the triggering glyph was used, no matter what. Now let’s look at a feature where the substitution only takes place when additional criteria are met: contextual features.

Contextual features have opened up a whole new spectrum of possibilities, enabling you to define very individual rules on how glyph variants are triggered. They have allowed quite complex typographic ideas to be tunred into working fonts. You’ll find them extensively applied in script typefaces such as Liza (by Underware) or Studio Lettering (by House Industries) where letter variants are used depending on which glyph precedes/follows, keeping the flow within the words going. Another use for the contextual features are fonts that loop through letter variants like FF Trixie HD (by LettError) or FF Duper (by Martin Wenzel).

I know that’s all very abstract, so let’s proceed and define a more commonly used contextual feature for fractions. The contextual bit we need to consider is the divisor because all figures preceding it need to be numerators (small figures, superscript position) while the ones following it must be denominators (small figures, baseline position). The feature is designed to be flexible since it doesn’t trigger a predefined glyph holding a preassembeled fraction (like ¾). It allows any number of figures before and after the divisor.

Input: …|one|eight|slash|two|nine


Output: …|one.numr|eight.numr|fraction|two.dnom|nine.dnom


First let us create some classes for the various types of figures that help us to simplify the feature definitions, listing them in the right order with their proper names:

@standard = [zero one two three four five six seven eight nine];
@numerator = [zero.numr one.numr two.numr three.numr four.numr five.numr six.numr seven.numr eight.numr nine.numr];
@denominator = [zero.dnom one.dnom two.dnom three.dnom four.dnom five.dnom six.dnom seven.dnom eight.dnom nine.dnom];

This feature looks almost like any other but for the inconspicuous ' in the 3rd and 4th statement, marking the glyphs that we need to to transform to either numerators or denominators. All other glyph references in these two statements are used to define the context in which the substitution will take place. As in all features the order of the statements is of vital importance.

	feature frac { # my Fractions feature
		sub slash by fraction; # 1st statement
		sub @standard by @numerator; # 2nd statement
		sub fraction @numerator' by @denominator; # 3rd statement
		sub @denominator @numerator' by @denominator; # 4th statement
	} frac;

1st statement:

For proper fractions we need the glyph named fraction as our divisor, so if slash was used, this statement will change it.

Output: …|one|eight|fraction|two|nine


2nd statement:

Now we take the standard figures from @standard — still ignoring the context — and replace them by their resp. glpyh from @numerator

Output: …|one.numr|eight.numr|fraction|two.dnom|nine.numr


3rd statement (contextual):

All figures are now numerators (see 2nd statement). We now need to check whether a figure from @numerator is preceded by the glyph fraction. If that is the case, use the appropriate figure from @denominator.

Output: …|one.numr|eight.numr|fraction|two.dnom|nine.numr


4th statement (contextual):

Before we write our final definition we need to know what substitutions have taken place in the previous statement. So when the feature finds the sequence of denominator|numerator it change the numerator figure to appropriate @denominator.

Output: …|one.numr|eight.numr|fraction|two.dnom|nine.dnom


For good usability it might not be desirable that the standard figures are turned into numerators right away (2nd line) without the presence of the fraction glyph.

Can I use contextual substitution in any feature?

No, integrating contextual substitution should be confined to features that are expected to hold statements of that type. If, for example, your ligatures use contextual substitution you shouldn’t use the standard ligatures feature, liga, but instead use clig, the contextual ligatures feature. When you choose «Ligatures» in InDesign, both, liga and clig are applied.

If it doesn’t work

Sometimes features don’t do what they are supposed to. Usually syntax errors are easily corrected but logical flaws in a feature can be challenging. FontLab can detect an error in your syntax — for example, if a semicolon is missing, if your feature name at the beginning doesn’t match the one in the end, or if two classes don’t consist of the same number of glyphs. Outside of these syntax errors, the program does not know what you are trying to achieve. It can not detect logical errors as illustrated in the following examples.

Statements in the wrong order

Depending on which glyphs you want to replace, the order of your statements can be of the utmost importance. Let’s take the ligatures feature from the beginning of the article — but swap the order of the statements:

	feature liga {
		sub f i by f_i; # 1st: if the sequence f|i is found, replace
		sub f f i by f_f_i; # 2nd: if the sequence f|f|i is found, replace
	} liga;

Now look closely at the following output and notice that the replacement of the sequence f|f|i doesn’t work as desired anymore. What happened now is that the first line caused f|f|i to be turned into f|f_i, thus f|f|i triggering the ligature glyph f_f_i isn’t available anymore.

Input: R|e|f|i|n|i|n|g|space|a|f|f|i|n|i|t|y|question


Output: R|e|f_i|n|i|n|g|space|a|f|f_i|n|i|t|y|question


So if you have an overlap in your replacement pattern (in both statements we are looking for f|i), make sure to put the longer sequence before the shorter.

Glyphs in classes/lists don’t match

When you define lists/classes you need to make sure that the resp. positions of the glyphs are corresponding, otherwise you’ll end up with results like the following. Here a has been replaced by g.salt and g by a.salt:

Input: D|o|n|quoteright|t|space|e|a|t|space|m|y|B|a|g|e|l|exclam|exclam|exclam


Output: D|o|n|quoteright|t|space|e|g.salt|t|space|m|y|B|g.salt|a.salt|e|l|exclam|exclam|exclam


This undesirable result is caused by the mix-up of the first and second position in the two lists: a and g.salt are listed first, g and a.salt second.

	feature salt { # my Stylistic Alternates, mixed up
		sub [a g] by [g.salt a.salt];
	} salt;

Not considering replaced glyphs

So far we have replaced glyphs that were in their basic state (a became a.salt). However, there are cases when you need to consider that a substitution might have already taken place, such as when the font contains more than two sets of figures (tabular, oldstyle, superscript ,…).

Example: your standard figures are tabular but the user has chosen to work with oldstyle figures and would like to change these to superscript figures. If your feature definition only lists the tabular figures to be substituted by superscript figures, then the user would see no change to the oldstyle figures. So you must consider the tabular figures as well as the old-style figures in your feature definition.

	feature sups { # Superior Figures
		sub @standard_figures by @superscript_figures; # standard to superscript
		sub @oldstyle_figures by @superscript_figures; # oldstyle to superscript
	} sups;

Which feature works in which program?

Current layout and design applications usually support even the most sophisticated features. However in standard office programs you’ll find that there are some limitations, especially regarding contextual features. Check out the following table to see which feature and substitution type works in which application (this table is an update of Typotheque’s OpenType feature support in applications).

Proportional Oldstyle pnum + onum
Tabular Lining tnum + lnum
Proportional Lining pnum + lnum
Tabular Oldstyle tnum + onum
Standard Ligatures liga
Discretionary Ligatures dlig
Historical Ligatures hlig
All Caps case + cpsp
Small Caps smcp
Capitals to Small Caps c2sc
Superscript sups
Scientific Inferiors sinf
Subscript subs
Ordinals ordn
Titling Alternates titl
Swash swsh
Contextual Swash cswh
All Alternates aalt
Contextual Alternates calt
Contextual Ligatures clig
Fractions frac
Alternative Fractions afrc
Numerator numr
Denominator dnom
Ornaments ornm
Stylistic Alternates salt
Stylistic Sets ss01…ss20
Historical Forms hist
Slashed Zero zero
Justification Alternates jalt
Alternate Annotation nalt
Mathematical Greek mgrk
Localized Forms locl
Petite Caps pcap
Capitals to Petite Caps c2pc
Unicase unic
Glyph de/composition ccmp
Required Ligatures rlig
Mark Positioning mark
Mark-to-mark Positioning mkmk
Mark Positioning via Subs. mset
Terminal Form fina
Initial Form init
Isolated Form isol
Medial Form medi

Which features are activated by which menu item?

The way programs handle the activation of features doesn’t always explain what precise feature is being called. Hover over/click on the highlighted areas in the following screen shot from InDesign and notice which features are applied.

All Caps icon

Changes all letters to uppercase and activates the features case and cpsp, same as menu below

Small Caps icon

Activates smcp, same as menu below
Note: if no real small caps are available InDesign will use capitals and scale them according to your settings in Preferences > Advanced Type

All Caps

Changes all letters to uppercase and activates the features case and cpsp

Small Caps

Activates smcp
Note: if no real small caps are available InDesign will use capitals and scale them according to your settings in Preferences > Advanced Type


Activates liga and/or clig

Discretionary Ligatures

Activates dlig and/or hlig


Activates frac


Activates ordn


Activates swsh and/or cswh

Titling Alternates

Activates titl

Contextual Alternates

Activates calt and/or clig

All Small Caps

Activates c2sc and smcp

Slashed Zero

Activates zero

Stylistic Set

Activates stylistic sets ss01, ss02, ss03,…ss20. Selection via sub menu

Positional Forms

Activates terminal forms (fina), initial forms (init), medial forms (medi), and isolated forms (isol). Selection via sub menu


Activates sups

Subscript Inferior

Activates subs


Activates numr


Activates dnom

Tabular Lining

Activates tnum and/or lnum

Proportional Oldstyle

Activates onum and/or pnum

Proportional Lining

Activates pnum and/or lnum

Tabular Oldstyle

Activates onum and/or tnum

Default Figure Style

deactivates figure related features, including lnum, pnum, onum, and tnum

Activated by default are the features Ligatures (liga), Contextual Alternates (calt) and the Default Figure Style.
Square brackets: If the menu item is in square brackets the font does not include the associated features.

You want to know more?

For all who want to get serious about this subject, we’ve compiled a list of links for further reading with more examples and pointed explanations.

Tools & Helpers

Testing your fonts


What's in a font?

About the authors:

Martin Wenzel: He’s a Type and Communications Designer in Berlin, Germany. After earning his degree at the Royal Academy in The Hague, The Netherlands, he worked with Petr van Blokland in Delft for several years while setting up his one-man design studio Originally a Berliner (not the jelly doughnut variety), he relocated to his hometown in 2005 to expand his design and font portfolio. Several of his typefaces are published under the FontFont label, including his award-winning sans-serif typeface FF Profile and last year’s FF Duper (both appearing in this article). He has recently launched his own foundry,, which debuts his latest typeface Ode, also featured in the above article.

Christoph Koeberlin: I take care of FontFonts at FontShop International, show what’s nice about type on, spend every second that’s left with my wife and children and I’m glad that I could contribute to Martin’s article. (Martin: Christoph, I’m really glad you did. You where an enormous help!)