In this article, I’ll discuss the problems solved by, and the design principles behind, my small open source project DynamicButtonStack.
Typically when a range of action buttons are presented to the user in an iOS app, the buttons are either stacked horizontally in a toolbar or vertically in a scrolling list.
The problem with toolbar-like layouts is there is limited space to grow. Bars are typically given a limited amount of height so that they don’t take too much space away from the main content area.
Icons on buttons help with fast recognition, but the meaning of icons can be unclear. On the other hand, button titles can clearly explain what the button does, but are harder to scan. Toolbar buttons usually have to pick between either an icon or a title because there is insufficient space for both.
When button titles are used, space can be limited with certain localisations, which can encourage the use of abbreviations or other terms that are shorter and not as clear. For example many words require more space in German compared to other languages.
Perhaps worst of all, in a toolbar there is no space to accommodate users who prefer larger text and icons. This was well put in this tweet from Marc Palmer:
There are a lot of people in the middle ground between VoiceOver users and default text size users who are IMO not well served by current UI design patterns where key UI elements don’t scale.
To address this to some extent, Apple created the Large Content Viewer. When the system text size is set to an accessibility size, an overlay showing a large icon and text label appears in the middle of the screen when the user holds down on a button. You can learn more about it in WWDC 2019 session 261: Large Content Viewer - Ensuring Readability for Everyone. However, as discussed in this session, making content readable to begin with is preferred over relying on the Large Content Viewer.
Showing buttons in a vertically scrolling list solves the space problem of toolbars. We can use contextual menus or
UITableView with self-sizing cells to get unlimited space. More content just means more scrolling. The downside is that showing a menu like this typically involves a screen transition. It is a much more heavyweight interaction compared to tapping an item in a toolbar.
In situation where a vertical stack of buttons can be shown inline with other content, it may take up more space than needed for a small number of actions.
Hybrids of horizontal and vertical stacks of buttons are showing up in Apple‘s apps. Maps uses one on the place details screen. It has three layout modes: fitting three, two and one button across the width respectively. This scales pretty well, although the ‘Add to…’ title is truncated in German at the largest text size.
The iOS 13 Mail app shows the first four buttons in its reply/actions sheet in either a two-by-two grid or a vertical stack.
I took a somewhat similar approach in my reading app. The app is designed to provide a stable and focused environment for reading. I did not want either an anchored toolbar on the reading screen, or to require the user to tap to show and hide bars. The reading screen is for reading. Buttons for taking actions on an article are only shown at the end of the article, in the content area.
With DynamicButtonStack, I’ve extracted my implementation of hybrid button stacking from my app. Depending on the content to be displayed and the space available, the button stack dynamically switches its layout. This means it can be highly compact if possible, but it will take up as much space as needed to ensure usability.
DynamicButtonStack has four layout modes, from most vertically compact to least vertically compact:
You can add as many buttons as you like. As well as dealing with any text size, it’s ready for localisation, including handling right-to-left layouts:
Give the content as much space as it needs
DynamicButtonStack is intended to be used in a scrollable area, so conserving space is not a goal. The stack will calculate the smallest possible size for its buttons given that readability is not compromised.
Image and title
Since saving space is not a goal, all buttons include both an icon and a title to provide the best of both worlds with comprehension and fast recognition.
Don’t stretch the layout
When given more space than it requires, DynamicButtonStack will more comfortably fill the space by using a more expanded layout rather than stretching the most compact layout that fits.
All buttons are laid out the same way. If one button requires the image and title to be vertically stacked, then all buttons will be stacked that way.
Unlike Apple Maps, the buttons won’t use horizontal stacking with wrapping. Instead it will switch to vertical stacking.
The icons and titles are always aligned in a regular way that aids the eye in scanning. You can see this in the third layout mode, where the icons are all centred on a vertical line, and so are the leading edges of the titles. (The iOS contextual menus and share sheet ought to work like this too.)
Define layout, not appearance
DynamicButtonStack deals with layout, but is hands off about all other aspects of the button appearance. Apps using DynamicButtonStack can make the buttons in the stack look as they like. Flat, skeuomorphic, neumorphic — it’s up to you.
I’d love to hear feedback about this. You can find DynamicButtonStack on GitHub, and let me know what you think on Twitter.