At the end of 2019, our product design team at ServiceTitan made the decision to transition from a constellation of design tools — Sketch, Invision, Zeplin, Abstract — to only Figma. The design system team, which had maintained several hundred Sketch assets, was now tasked with deprecating this setup for its Figma equivalent. This post will talk about our journey, with the ups and downs of supporting a new program.
Who we support with our design system
ServiceTitan is a cloud-based software platform for field services. Verticals the company covers include plumbing, HVAC, electricians, and many other technical trades. The scope of the platform is vast, providing products for business functions such as phone service, dispatching workers, inventory management, marketing, and many other product lines. While a relatively new company, ServiceTitan is large enough to staff many product designers, and have dedicated resources for an internal design system.
Our work, named Anvil, is an in-house design system that seeks to meet the demands of a rapidly growing, enterprise software. Begun in mid-2018, Anvil is a design-led, ongoing project that was built from scratch. Its internals reside in code (via React), provides design guidelines, documentation, and design artifacts.
While Anvil is a design-lead initiative, its source of truth is in React code, not in our design files. To be formally apart of our design system, a component must be coded and available to the engineering team, with design files being built from this coded version. By extension, our team is responsible for all of the design system’s lifecycle, from user research to producing production-ready code.
From Sketch origins to the world of Figma
Anvil started off by supporting Sketch, since that is what the existing team used. A core attribute to the design system is its code source of truth, and this logic extended to our handling of Sketch assets. We were able to automatically generate our Sketch symbols through a forked version of html-sketchapp. Symbols would then be version managed through Abstract. This process insured that any time we made changes to a design component in code, Sketch would automatically update to reflect the change.
Overtime however, the product design team wanted to completely switch their workflow over to Figma. This transition would test how well our design system could adapt to majors shifts from the user base.
From automatic Sketch symbols to manual Figma components
Figma at the time of this writing does not have an adequate Code → Figma process. The foundation of our Sketch process was built on automatically generating hundreds of Sketch symbols from our codebase. Despite Sketch and Figma being relatively similar programs for end users, supporting Figma required us to completely remake our process of creating design artifacts.
The product design team did not move tools overnight. Change took place over a few months. The design system team would be a bottleneck if it waited around for a formal decision from the team. Feeling reasonably confident the change would happen, we began this project several weeks before the designers moved their projects to Figma. We ultimately supported Figma a few weeks before the design team began full usage of it.
For this project, we would need to:
- Figure out how to build assets for Figma for the long term
- Adjust our version control process from Abstract to Figma
- Determine contribution and release guidelines
- Learn Figma itself
Building out assets in Figma
A solution in 1 minute: Import the Sketch Library to Figma
Since our whole design system was already Sketch, the obvious thing to first try is just importing the Sketch file to Figma. It worked, kind of.
There were quirks as you might expect in an auto conversion. The common problems included box-shadow spread mistranslations, lots of missing borders, line-height miscalculations, and CSS pseudo selector mistranslations from code → Sketch. It worked, after you made micro adjustments to a hundred or so components.
Long term solutions for Figma
A straight import wouldn’t sustain us for long. We evaluated a few different processes that could best bring parity to our codebase:
Option 1: Continue to generate Sketch symbols, and use Figma’s import functionality to pull in the Sketch file. We would manually clean up the imports.
Pros: Easy, and fast. We already have the Sketch assets, and we could continue to generate new ones in the future through our existing code setup.
Cons: The component quality would be inferior to Sketch symbols. We would have to continue to support the technical infrastructure of generating Sketch Symbols. It would make little sense to support a design program no one else is using.
Option 2: Manually recreate each Figma component
Pros: Highest quality assets. Would be able to abandon our forked codebase for generating symbols. Not constrained by auto-generating limitations.
Cons: Time consuming to create, difficult to maintain, easy to create discrepancies with code.
Pros: Reinforces concept of code as a source of truth, potentially easiest to version control, potentially most accurate.
Cons: These tools are still in active development. It is exciting to see progress, but they aren’t yet ready for an enterprise environment.
In weighing each solution, only one appeared viable, at least for the next several months. We would need to go with option 2, manually create each Figma component, and end our Sketch Symbol production.
Making a few hundred components
Over the course of a few weeks, components were laboriously recreated. Visual parity was not too difficult since the Sketch variations already met that. Here are a few notable events from this process:
- We had to rethink our layer structure since our symbols literally reflected the underlying HTML structure. We ended up producing better quality components relative to our symbols.
- There was some time adjusting to frames and constraints. It took some trial and error to get text and layout positioning correct when adjusting component instances. After awhile, this became easier for us.
- We had the blessing (and curse) of receiving the Auto Layout feature towards the end of our work. It’s a powerful and highly anticipated feature, but had a few noteworthy limitations. While it gave us better layout adjustments, width and padding limitations prevented it from being useful for components that needed width adjustments. As a result, only about half of these components ended up with auto layout.
- One of the features of our components was hidden layers of content. Toggling them would surface new features, such as icons and badges. Our symbols could not rely on this tactic, which helped cut back on our total component count.
Thanks largely to one person on the team, we were able to port our design system into Figma in time for the design team to use it. Our bugs were relatively light, and it didn’t take long for the Figma components to be superior to their symbol counterparts. Easily our biggest issue was its management, mentioned later in the challenges section.
The day-to-day differences in supporting Figma
The change from automatic to manually created design artifacts is where the bulk of both our pros and cons come from.
Benefits to supporting Figma over Sketch
Superior quality of design system artifacts. Automatically generated symbols can only be so high in quality. Structure that made sense in React didn’t make a lot of sense as folders in Sketch symbols. The human touch unsurprisingly created a better UX for the assets themselves.
No longer supporting a forked library. Our html-sketchapp tool was forked and had active internal refinement. Bugs happened, CSS hacks were sometimes used. Dropping support for Sketch meant less development resources for this tool. Some of our biggest pain points with the design system as a whole was getting this program to translate our code well, and we do not miss this headache.
Design collaboration is superior. Since the design system team would also use Figma to work on new projects, we ourselves benefited from its collaborative tools. This is even more true when our work is all remote. We sometimes had to open up Sketch for legacy work, and it felt like we were going back in time.
Abstract had a tendency to eat work. If you didn’t use the software properly, sometimes people would lose a huge amount of work. Our generated system did not suffer from this, but it did occasionally happen with design explorations from various designers.
Challenges to supporting Figma
From the perspective of design systems, a lot of our challenges are tied to its management. There are certainly some more common asks such as more fleshed out auto-layout features and more powerful search, but those are mostly nice to haves for us.
Version control isn’t quite up to what Abstract can do. With Figma, modifying our library feels like maintaining a codebase that only exists on production, that many people can edit. Several times we have had unaccounted for modifications and deletions to our library, often taking days to even detect. With Abstract, our Sketch library had a much better process: branching, more robust commits, superior permissions handling, easier and safer reversion. We haven’t had the Figma library completely break yet, but it feels more like a question of when, not if.
Increased breaking changes in library updates. One way to deal with the version control issue is mimicking a common code workflow of local and staging environments. Backups are ready, production gets updated with what is in those other environments. Problem mostly solved, right?
The issue with this comes down to unique IDs to components. Figma uses some sort of unique ID behind the scenes for its assets, and they don’t quite follow components across copy/pasting or layer recreation. Take this example: A simple button exists in your library, with proper layer naming, a text layer, and a background color. Inside the component, you delete one or both properties, then recreate it with the exact same properties and name. You publish your work. If consumers of your library update, all of their button instances will get reset.
We have broken many of our components this way. Buttons, input fields, tabs, all start having default values in dev handoff files. Developers have to do a lot of back and forth, and designers end up taking the blame for looking sloppy. It is too easy for someone to go in and break the IDs on accident, and once they do, there’s hardly any detection system for us. We have done some makeshift testing with internal instances, but lacks the visual regression powers of Abstract.
When we auto-generated Sketch symbols, we got around this problem with slugs. Here is an example of such code:
name='Button/Large/Solid/Primary' /* Symbol directory setup */
slug='button-large-solid-primary' /* Unique symbol identifier */
<Button large primary>Button</Button>
As long as we maintained the same slug throughout the component’s life, every update had continuity, even if we revamped all of the behind the scenes aspect of the component.
Increased release management overhead. A byproduct of these issues is the increased overhead in maintaining Figma assets. Sketch assets would only be updated following a code release. As long as we knew what was in code updates, we also knew everything that would change in the symbols. With Figma, all UI updates in code requires manual Figma updates. In addition, Figma could be updated independently to code updates. We now needed to track all Figma updates, worry about the hidden problems mentioned earlier, and have a communication strategy just for Figma. These process changes adds a non-trivial amount of project management and communication overhead. How can we be sure the code updates are in Figma? That they accurately represent what is in code? Who is keeping track of all the individual contributors to the library?
A more accessible, public roadmap and release callout would be nice. Sketch as a whole was easier to predict about what they were up to. With Figma, it’s a lot of guesswork, looking through Slack groups, Twitter threads, and their blog. Being in product development, I know the trouble of having a public roadmap, but it would still be nice to know the general direction.
For updates, Sketch’s updates page provides valuable release information, which has helped us identify what’s changed and what bugs might happen or be resolved. With Figma’s release page, a lot of information falls through the cracks, making it difficult to know what’s really changed.
Things we’re looking forward to with Figma
- Number one for us is better version control and general guardrails. Next to Abstract, our Figma library library feels so fragile.
- Refined Auto Layout options. Like most other Figma users, we’d love to see better width adjustments and padding options.
- A Figma code tab that integrates with our codebase. Since leaving the Zeplin workflow, we’ve been eyeballing their connect component feature.
- Continuing to refine our own process with Figma.
Was it worth it?
A design system should ultimately support whatever tools its designers want to use. We knew early on that tools can change, and are always committed to empowering their workflows. Our strategy of code as the source of truth gives us this flexibility. The time spent adjusting to a program was ultimately worth it for everyone, and while version management could be better, we also feel confident that Figma will continue to rapidly evolve.