Monospace Digits

A quick tip for displaying digits with a fixed-width, monospace font, when you don’t want a “computer style” typeface.

Monospaced fonts

I want to display the hour, minute and seconds of some timers. Using the standard system font the digits have proportional spacing so they don’t vertically align and jump around as the digits change:

Two timestamps using a system title font

There are a few ways to tell SwiftUI to use a fixed width font. For example, with a fixed size system font use the system(size:weight:design:) method. For dynamic type styles use the similar system(_:design:) method. Either way choose a .monospaced design:

VStack {
  Text("12:34:56")
  Text("07:18:19")
}
.font(.system(size: 72, weight: .regular, design: .monospaced))

The UIKit equivalent has the same effect:

timerLabel.font = UIFont.monospacedSystemFont(ofSize: 72,
  weight: .regular)

That uses the SF Mono typeface from the system San Francisco font family and gives a computer text appearance to the digits. This adds a noticeable foot to the digit one, an open digit four, sixes and nines with straighter tails, and a slashed zero:

Two timestamps using SF Mono fixed width font

This computer style typeface isn’t always what I want. Compare SF mono to the appearance of the stopwatch timer in Apple’s Clock app:

Apple stopwatch showing 01:24.91

The digits still have a fixed width but it’s using the standard San Francisco font (compare the “0”, “1”, “4” and “9” with the previous example). If you look closely you can also see that the “:” and “.” separators are not using a fixed width. This gives a different feel to the timer whilst still maintaining an overall fixed width.

How can we apply that same design to our view?

Monospaced Digits

Browsing the SwiftUI, UIKit and AppKit documentation, it turns our there’s a method for each of those frameworks that produces a version of the system font with monospaced digits but keeps all other text proportionally spaced.

For SwiftUI, there’s the monospacedDigit() view modifier:

VStack {
  Text("12:34:56")
  Text("07:18:19")
}
.font(.system(size: 72))
.monospacedDigit()

For UIKit and AppKit, you can get the same font from the monospacedDigitSystemFont(ofSize:weight:) method of UIFont or NSFont.

timerLabel.font = UIFont.monospacedDigitSystemFont(ofSize: 72,
  weight: .regular)

This matches the design of the stopwatch, the digits are fixed width, so they align vertically, but use the default system typeface. The proportional spacing of the “:” separators is also noticeably less than the digits:

Two timestamps using system font and monospaced digits

Read More