Building a Design System Library

How we created the Lyft Product Language attributes and component libraries

Jeremy D.
Jeremy D.
Aug 10, 2020 · 11 min read

At the end of 2019, I helped move all of Lyft’s design system from Sketch to Figma. Ironically, this was one of the last projects I worked on prior to leaving Airbnb as well. What I learned from these two experiences helped me recognize some fundamental things that everyone should consider when designing a shared library within Figma, the design tool of choice at this time.

Zoomed in view of Figma project folders with files in them.
Zoomed in view of Figma project folders with files in them.

In this blog post, I want to discuss some best practices that we followed to create the multiple Lyft Product Language attributes and component libraries. And at the end, I cover some helpful tips and tricks that allow us to efficiently maintain them today.

System-ception: a system within a system

When we started to tackle creating our system in Figma, we took a step back to reevaluate what we’d done in Sketch, questioning the decisions we’d made about layout, visual hierarchy, and naming convention, to name a few. We realized that in order to create a strong foundation in these new libraries, we had to take the time to create a system within a system that would apply to every element in the file. In the end, we essentially built in a certain level of quality and consistency into the library which allowed us to scale the number of library maintainers.

Carousel Page Indicator main and internal components. Note the file canvas has a #F4F4FA background fill.

We set up each component page with visual hierarchy to help distinguish between the main components and the internal components that make them up. All the main components are placed in frames that have a 4px inner outline without a background fill. These Frames act as the component sticker sheet.

The internal components are placed in a Frame with a white background. Displaying all of the internal components allows the maintainer a snapshot of the options that can be used to reconfigure the main component. The goal of these internal components is to allow a user to reconfigure a main component into the variation they need and to promote shared internal components, making it more efficient to maintain.

A system of padding

In each Frame, there is specific padding used. The benefit of considering a system of padding is that it creates a visual consistency between all the elements on the canvas, from page to page, and library to library.

Our component libraries utilize these paddings:

  • 60px: Internal Frame padding (top, right, bottom, and left)
  • 40px: Between Frame title to 1st main component
  • 24px: Between Frame title to Subtitle (optional)
  • 24px: Vertically between main components
  • 40px: Horizontally between main components
Layers reordered visually from top to bottom

By default, when adding layers in Figma, the new layer is created above the current one in the Layers panel. A bookkeeping and tedious task is reordering the layers from top-to-bottom, left-to-right, based on the visual hierarchy of the Frame.

When managing a large number of main components and internal components, mapping the layers in this way allows the maintainer to quickly navigate a sometimes chaotic canvas.

Naming convention applied to the focus compact button

After facilitating a quick survey in Slack with users, we discovered that the majority of them use the Assets Panel to search for and discover components. How components are named is important to this workflow.

We created and applied this naming structure to all of our components:

File name / Page name / Frame name / Component name (variation, style, type & state)

The file name is the name of the specific library and what users will need to enable in the Assets panel in order to use the components in their mockup files (ie. Core UI Components (Android/iOS), Core UI Components (Web), Core UI Color, etc).

The page name is the name of the component (ie. Carousel Page Indicator, Button, List Item, etc).

The frame name is the top-level grouping of the component, usually the size (ie. Buttons have 4 sizes: Focus, Focus Compact, Drive, and Drive Compact).

The component name is the name of the main component and its variations. Due to the number of variations, using the backslash ( / ) allows them to be categorized into other defining categories, like states. Even though this essentially places them into more “folders”, this helps bucket similar variations to be easily swapped in the Instance dropdown and discovered in the Assets Panel folder structure.

Visual of the folder structure in the Instance dropdown

More flexible components

Creating atomic elements is the foundation of a design system. The Lyft Product Language is broken into atomic elements and then used to create specific components. These internal components help provide consistency across a large team (ie buttons) as well as cut down on maintenance, especially when these internal components are shared across multiple components (ie text field, text area, dropdown, etc).

List item component consists of 3 areas: Start, Middle, and End

The best example of how internal components make up a component can be seen in our List item. This component is set up with areas that can be reconfigured to create a number of variations. Under each area, there are different internal components you can choose from. Plus, by structuring them at the same size, only those choices are allowed for each area (ie there are only 4 internal components allowed for the Drive Default’s Start area).

Internal components allowed for the Start area
Internal components allowed for the Middle area
Internal components allowed for the End area

For a complex component like List Item, internal components are valuable to allow the flexibility of reconfiguring a component to fit various use cases.

Let’s talk about responsiveness

There are other things to consider when creating flexible, shared components that respond in the exact way you intend. A lot of these options can be defined in the Design panel within the Figma interface.

The design panel in Figma: source

Creating responsive components is important to promote adoption across all users since most apps support various screen sizes and platforms. A way to achieve this is by defining how your component’s layers resize accordingly based on what you set for the Horizontal and Vertical constraints.

Horizontal constraints: source
  • Left pins the layer to the left side of the frame.
  • Right pins the layer to the right side of the frame.
  • Left and right allows the layer to grow or shrink along the x-axis.
  • Center allows the layer to float towards the horizontal center of the frame.
  • Scale allows the layer to grow or shrink as a percentage of the Frame’s dimensions.

An example where it’s a good idea to set horizontal constraints is when resizing a List item component where you want an icon stay in the same location while allowing the text layer to grow or shrink.

To do this, simply set your Start layer to a left horizontal constraint and your Middle layer to a left and right horizontal constraint.

Example of horizontal constraints settings for a List Item component.
Vertical constraints: source
  • Top pins the layer to the top of the frame.
  • Bottom pins the layer to the bottom of the frame.
  • Top and bottom allows the layer to grow or shrink along the y-axis
  • Center allows the layer to float towards the vertical center of the frame.
  • Scale allows the layer to grow or shrink as a percentage of the Frame’s dimensions.

An example where it’s a good idea to set vertical constraints is when resizing a Text area component where you want the message layer to pin to the bottom while the text area outline to grow or shrink.

To do this, simply set your Message layer to a bottom vertical constraint and your Text frame layer to a top and bottom vertical constraint.

Example of vertical constraints settings for a Text Area component
#8 bullet — type resizing options: Auto Width, Auto Height, and Fixed Size: source

In a similar way of constraints, there are some controls you can set on your type layers to accommodate shrinking or growing based on its content. This works in conjunction with the constraints you set.

This option allows your text layer’s width to grow based on your content. I typically set a text layer’s width to auto width when wanting my layer to grow based on my content. By setting the horizontal constraints to the left along with the auto width option, my text layer will resize accordingly.

Example of auto width text settings for a Text Area component

This option allows your text layer’s height to grow based on your content. The original text layer’s width will dictate when your content wraps to a new line. I typically set a text layer’s height to auto height when wanting my content to wrap to a second line within a component. By setting the horizontal constraints to left and right along with the auto height option, my text layer will wrap the way I intend it to.

Example of auto height text settings for a Text Area component

This option sets your text layer’s width and height, no matter the content. The text layer’s set width will dictate when your content wraps to a new line and will extend past the text layer’s set height without being clipped.

Another way to create flexible components is by utilizing the Auto Layout feature which responsively adjusts components based on your content. Components that work really well with Auto Layout includes Buttons, Lists, and Panels. But this feature has its limitations and will be up to you to decide to utilize it in your components.

Responsive buttons using Auto Layout: source

Auto Layout frames can have their own padding, fill, stroke, and corner radius which is all you need to create a button. As you input your content, the frame resizes automatically, keeping the padding you set. This also applies to stacked buttons with Auto Layout.

Wrapping text shifts other elements: source

Being able to copy-and-paste content into your text layer which in turn shifts the rest of the elements in your design shows how powerful Auto Layout is. This is a great way to test for localization as well!

Automatic reordering is easy with Auto Layout: source

Ever find it tedious to reorder repeated UI elements like within a list or menu? Auto Layout allows you to reorder them by simply dragging and dropping them or using the up and down arrow keys on your keyboard.

Tricks of the trade

I utilize keyboard shortcuts on a daily basis to help me work more efficiently within all the component libraries the Design System team manages. Some of these exist in other design programs and others are neat pro-tips that make it easier to work in Figma.

  • Select All with Same Instance. When needing to rename a number of internal components within a page full of main components, simply navigate to the Edit menu and select Select All with Same Instance.
Edit > Select All with Same Instance: source
  • Create a component. Any design system designer knows they’ll be creating components until the cows come home. I type Option + Command + K frequently to quickly create a component.
  • Rename layer(s). Figma’s default renaming feature is super powerful. Selecting multiple layers and typing Command + R triggers a Rename Layer modal with more renaming options including find and replace, ascending and descending numbers, and prefixing or appending to the current name.
Command + R when multiple layers are selected: source
  • Paste over selection. Paste in place, for those who cut their teeth in Illustrator, was the most common feature I used. In Figma, you simply type Shift + Command + V (while something is already selected) to accomplish this.
  • Zoom in on layer. To quickly zoom in on a layer, simply double click on that layer’s icon in the Layers menu.
Quickly zoom in on any layer: source
  • Component descriptions. This is a way to communicate specific details about your component. It displays when you hover over an Instance in the Assets and Code panels. We utilize this area for handoff information to our engineering partners.
Engineering handoff information placed in the component description: source
  • Ignore constraints. Sometimes you want to temporarily ignore the horizontal and vertical restraints you set on your component layers. To do this, simply hold down Command while resizing your component. Release Command if you want to honor the constraints.
  • Prevent auto nesting. A frustrating thing I discovered when moving layers around the canvas is it would automatically place them in other frames. To prevent this from happening, hold Spacebar while dragging your layer around.
  • Instance swapping. This is a pro-tip that can be used to swap any instance but I’ve used it specifically to replace icons; hold Option when dragging a component from the Asset panel. There’s an added efficiency as well since you can use the Asset panel search field, too.
Replace icons like a boss: source

Last thoughts

When I first created Airbnb’s component library, it was the first time I ever touched a design system. I learned as the library materialized and thanks to the system within a system concept that I utilized at the beginning, I was able to take something as complex as a design system and present it in a way that had consistency, quality, and flexibility built into its foundation. That’s the recipe for how I helped build Lyft’s design system in Figma. Are there any best practices that you’ve utilized to build your design system? Leave a comment below!

This article was written by the extremely talented Jeremy Dizon — currently a production designer on the Lyft Design Systems team. Please subscribe!

Tap to Dismiss

Sweating the details so you don’t have to