Semantic Colors for Designers and Developers (3 Part Series)
We believe that a design system isn’t worth much if it’s only used by designers. So when we started working on this new approach to colors, we knew we wanted to make it simple and usable for developers, too.
So we built a Figma integration that takes all of the color information from our color file and outputs usable code (special thanks/shoutout to Kyle Robinson Young on the YNAB development team, who helped build the integration).
YNAB offers an iOS app, an Android app, and a web app. We rely on our design system to keep things consistent between each platform, so the integration outputs code for each platform.
Each platform has some idiosyncrasies as far as how colors are defined and how light/dark mode switching happens, so we’ll run through each of them.
For iOS, the integration outputs a color file that is broken into two sections. This is where all of our iOS app's colors are defined.
The first section of the file defines the palette colors. These are private because we never refer to them directly — instead, we refer to semantic colors. This keeps things consistent and guarantees that they look good in light and dark mode.
In the next section of the file, we have our semantic color definitions. These are what actually we use to apply color. Each and every semantic color points at a palette color for light mode and for dark mode.
One of our iOS developers wrote a simple function, that looks at the user’s display mode and determines which color variant to display. That way, things will “just work” between modes. We also built in a safe fallback, in case users aren’t running iOS 13 yet.
We use the description field of the semantic colors from Figma to populate the proper references to the base palette for each semantic color.
For Android, the integration outputs to three color-related files.
palette.xml. This is the base color palette where all possible colors are defined.
colors.xml (night). These each have each semantic color listed, with the proper reference to the base palette for each mode — light mode definitions go in palette.xml and dark mode definitions go in
When we’re applying colors, we simply refer to colors defined in
colors.xml and the right variant renders based on the user’s mode.
We use Stylus for our web app, so we output a
As you can probably anticipate from the structure of iOS and Android,
palette.styl contains the base palette colors. ‘Colors.styl
and ‘dark-mode.styl contain CSS variable definitions that reference the proper base palette colors.
So when we are applying colors, we use the CSS variables we define in
dark-mode.styl and render the right variant based on the mode the user has selected.
We haven’t released dark mode for the web, so this approach is still experimental, but we’re confident it will work just as well as the system has been working for iOS and Android.
The fact that we output color definitions directly from Figma means that when a developer looks at a design, they can use the exact same name as the designer and the code will “just work.”
The Figma integration makes it easy and lightweight to keep the system up-to-date; relying on manual updates and communication for a system like this would be a surefire way for it to quickly get out-of-date, messy, and to start to diverge between different platforms.
With this system, we simply run the integration any time colors change in Figma (which is our “source of truth” for all things color). Then developers immediately get access to the latest and greatest colors.
But the technical specificities here are less important than the fact that the philosophy and the language around colors are shared between designers and developers. This system gives us a shared language for talking about colors, and empowers everyone on the team to pick the right color for the job.
That’s all for our series on how we built a semantic color system for designers and developers at YNAB! Feel free to reach out if you have any questions or suggestions. Our hope is that this system can be as useful to other teams as it has been to us!