When to use variants, component props, variables, or separate components

First, a brief review of where we’ve been.

Before variants, the only way we could organize Figma components was using forward slashes or frames to group and nest them together. This was fine, but it wasn't great. It forced us into very rigid folder systems.

Folks often asked, "what's the best way to order groups of components?" Figma's documentation has an example with the following hierarchy: <span class="inline-code">Operating system / Component name / Device / Color theme</span>. But are there advantages to that particular order? Would it make a difference if it was flipped and “Color theme” came first? I always felt like slash-naming was important to keeping a file clean and organized, but that the order of the folders I created were arbitrary. Of all the combinations I tried, I was never satisfied with the folder names or folder-order I came up with. Some were too rigid and convoluted, others were too loose to be useful. Finding that happy medium seemed impossible.

Variants introduced in October 2020

In late October of 2020 Figma introduced their variants feature. Not only was it a game changer for the experience of modifying instances in mockups and prototypes, it also gave us a new, even more powerful way to organize components: variants let us flatten the structures that slash naming forced us into. Variants allow all a component's, well, variations, to be accessed in any order. You no longer have to drill through a half dozen groups just to switch to dark mode.

Component properties introduced in May 2022

2 years later Figma announced component properties in May of 2022 at Config. This feature was largely in response to “variant explosion”, a term Figmates use to describe enormous variant sets. I definitely authored some sets that were far too big... my worst was probably a button component with over 1,600 variants.

Advanced users were quick to recognize the potential of component props, but felt it was lacking, and even causing confusion for their teams. After receiving this critique, Figma came through with a fast-follow release in the form of an open beta which introduced:

  • Exposing nested instances (in my opinion, this was the biggest quality-of-life enhancement Figma has provided since releasing variants).
  • Simplified instances
  • Preferred values

Variables introduced in June 2023

Designers had been asking for a feature like variables well before variants and component properties even hit the scene. At Config 2023 Figma delivered a first version of variables. This the ability for us to not only store number, color, string, and boolean values, but reference a variable within another variable downstream (this is called ‘aliasing’).

While component properties were a direct answer to variant explosion, I see variables as an indirect answer to the same issue. There’s a lot we’ve still leaning on variant properties for that can now be offloaded into variables.

<div class=”horizontal-rule”></div>

But variants, component props, and variables haven't made slash naming obsolete. Nor were they meant to! You should use a combination of all these features to organize your components and make them easy to work with. And, as ever, along with all these new features come new questions to answer... like, when should you use variants VS component properties? Are certain components better to separate with slash naming than adding another prop using variants? When do you reach for one method over the other? Are there any circumstances where slash naming still has an edge over variants? And where do variables fit into all of this?

Because this is a long post, here are some anchor links to help you skip to sections you're most interested in:

Always use variants for:

Always use separate components for:

Always use component properties for:

Always use variables for:

What about libraries?

  • Device/Operating system

<a href="#free-variants-separate-component-vs-component-properties-flow-chart" class="button secondary" style="padding:16px,0px; margin:auto; border-bottom:0px solid;">Jump to free flow chart resource</a>

<h2 id="always-use-variants-for">Always use variants for:</h2>

<h3 id="interactive-states">Interactive states</h3>

E.g. "default", "hover", "active"

Figma had to release variants in order to release their interactive components feature. Variants were were born to handle interactive states like hover and pressing. They work most reliably when the layer structure remains intact across every variant in the set (if you find you’re losing overrides when swapping variants, it could be your layer structure), which will be true in an overwhelming majority of cases when you're dealing with interactive states. These states manifest as changes in color, stroke width, and effects like shadow. Without a doubt, you should always, always, always reach for variants when componentizing interactive states.

<h3 id="binary-states">Binary states</h3>

Binary states are like a cousin to interactive states. The difference is binary states are, well, binary: you only get 2 options. What they affect must be described in the property name because the toggle switch in the design panel can only communicate “yes/no”, “true/false.” When deciding what to name a property that uses boolean values, think about the most sensible default state. Like Nathan Curtis talked about in his Schema 2022 talk, your instance users might prefer to have all options turned on and then prune away what they don't need. Others may appreciate the opposite, where they start with a very basic composition, and then add to it as needed.

Another nice touch is phrasing your binaries in the affirmative state so you have a match between the property name and the "true” value. Stick with this throughout your library. Here’s some examples:

  • Any component with an empty state, name the property <span class="inline-code">Populated</span> rather than <span class="inline-code">Empty</span>
  • A component that communicates whether we’re seeing a logged out or logged in experience. I’d name the property <span class="inline-code">Logged in</span> rather than <span class="inline-code">Logged out</span>
  • A component that has a disabled state. Some folks choose to lump this in with interactive state, but I personally think it makes more sense a distinct property. I talked about and demo’d this in my component library live stream series a while ago. The <span class="inline-code">state</span> variant you’d pair your <span class=”inline-code”>Enabled = true</span> would be “Default.”

<h2 id="always-use-separate-components-for">Always use separate components for:</h2>

<h3 id="icons">Icons</h3>

E.g. <span class="figma-component">◈ Icon / gear</span>, <span class="figma-component">◈ Icon / house</span>, <span class="figma-component">◈ Icon / pencil</span>

Bonnie Kate Wolf wrote a massively helpful piece for DesignSystems.com titled "A complete guide to iconography." You should bookmark this one. There's not a publication date on the article, but I'm pretty confident it was written before Figma introduced their variants feature, because she describes only using slash naming, frames, and pages to organize icon components—despite using the word "variant" four times in the article! I find this kinda funny, it's like she predicted the feature name.

Icons are things that you absolutely want to organize as separate components. I’ve seen folks make one big "icon" component as a variant set. Then they’ll set up a property called "name" and use that as the mechanism for swapping icons. Whether your collection of icons is just a couple dozen, or hundreds or thousands, this is bad practice because:

  • ❌ There is no visual preview in variant selection dropdown/picklists. Only the names of that variant. This makes scanning difficult, slow, and be a huge hinderance for designers who are new to the library.
  • ❌ There’s no way to narrow the list with search functionality, you have to know exactly what you’re looking for. Hopefully the list is correctly alphabetized (something that must be manually managed, Figma won’t auto-sort it for you).
  • ❌ On the performance end of things, this construction is equivalent to hiring a private jet to go somewhere you could’ve gotten to faster on your bike. A humongous waste of resources. Every icon variant in the set will be rendered in the background when you drop one of these on the canvas (see Figma’s documentation on this). This is what makes it possible to switch between variants instantaneously, even if you lost your internet connection. If you have 100 unique icons in your variant, and each only has 2 layers (the frame and the vector shape), you’d be weighing down your files with 200 layers for every single icon instance you use.

But how do I manage icon size?” If you need to offer icons at different sizes, I strongly recommend leveraging Ridd’s icon-wrapper method, and pair it with more modern features like instance swapping. If you have lots of sizes to manage, you can take Ridd’s method either further and do what Alex does: create a separate icon wrapper component for any icons that are more popular at a certain sizes. You should also think about your icons intent and use-cases to make this decision. For example an “X” icon might be used in many more sizes than a “fork and knife” icon.

What about interactive states?” Yes, this is when you want to deviate and use variants. You could also offer an “interactive” and “static” version of the same icon so consumers who don’t need or want interactivity don’t have to remove that prototype connection. Molly Hellmuth also endorses this approach.

What about icon fonts?” I don’t like using icon fonts for many of the same reasons I don’t like to have a single “Icon” component with variants for each unique glyph. You end up having to memorize the exact icon names in the set to be able to get the icon you need. That’s a heavy cognitive load designers need to take on just to use iconography in their designs.

<h3 id="HTML-tags">Foundational atoms and molecules with unique HTML tags</h3>

Eventually, engineers are going to reference your Figma components so they can build the product in real life. As much as we can align our Figma components to the structures of the real web, built on HTML, the less translation work we create for our developer colleagues.

HTML tags I try to watch out for include: <span class="inline-code">button</span>, <span class="inline-code">footer</span>, <span class="inline-code">input</span>, and <span class="inline-code">label</span>

<h3 id="interface-reps">Different ◈ interface representatives</h3>

E.g. <span class="figma-component">◈ Header</span>, <span class="figma-component">◈ Footer</span>, <span class="figma-component">◈ Button</span>, <span class="figma-component">◈ Card</span>

No one would combine their global navigation and footer as variants in a component named "global elements." They're separate chunks of interface that do different jobs, therefore they ought to be separate components.

If you’re curious why I’m referring to these as “interface representatives” and not just “components”, and what the deal is with the ◈ icon, you’re in luck! I’ve got a blog post all about it.

<h3 id="placeholders">✂︎ Placeholders</h3>

These components allow you to "edit" an instance's layers without detaching. If you haven't heard about these bad boys, watch Adam Przewoski's youtube tutorial about them. Or check out my other blog post about ✂ placeholders.

<h3 id="base-components">⍚ Base components</h3>

Remember, you’re better off not using ⍚ bases in your component libraries! They are better suited for iterating on ideas in local files. And naturally, they’re going to be their own separate components in order to be of any use to you.

<h3 id="content-carriers">✎ Content carriers</h3>

Similar to ◈ interface reps, ✂︎ placeholders, and ⍚ bases, ✎  content carriers have to be separate components for you to use them properly.

<h3 id="starter-kits">⍂ Starter-kits</h3>

Starter-kits are curated collections of instances of other components. They're fully intended for to be detached, therefore you want them to be their own components. The frame they come in is a temporary vessel.

<h3 id="hierarchy">Hierarchy</h3>

E.g. "primary", "secondary", "tertiary"

In the previous version of this blog post, Hierarchy was listed under “things you could use variants OR separate components for.” Now that I have more experience under my belt, I feel confident offering a more opinionated recommendation: handle Hierarchy as a separate component. The argument is that doing so will offer you and your library consumers:

  1. Better discoverability. Typically this argument is easiest to make when you focus on the asset panel. But one day I got curious and put a poll on twitter asking how folks like to insert components into their files. Turns out, there’s lots of ways to do this! Copy/pasting from the library file (or other local files), using the mini-asset panel in the top toolbar that you access with <span class=”inline-code”>shift</span>+<span class=”inline-code>i</span> are other common insertion practices. For folks who use the regular or mini asset panel, keeping <span class=”figma-component”>◈ Button / Primary</span> and <span class=”figma-component”>◈ Button / Secondary</span> as separate variant sets more discoverable.
  2. More flexibility to iterate on the separate components’ layer structures and APIs. Maybe your <span class=”figma-component”>◈ Button / Tertiary</span> doesn’t have icons. Maybe <span class=”figma-component”>◈ Button / Secondary</span> allows for an optional little split-button composition, but the same isn’t true for <span class=”figma-component”>◈ Button / Primary</span>. Splitting out your components as separate variant sets gives you the flexibility to handle these architectural nuances. This is also a win for component usability because you can ensure the properties panel is all killer, no filler. Another way to say that is: every property is relevant to every variant in the set.
  3. Unlocked opportunity for independent versioning. Imagine you’re handling hierarchy within a single variant set. If you’re tweaking the visual design of only the “Primary” button variants, you still have to publish the entire component set (even if none of the other variants changed). Now imagine you handle hierarchy with modes in a component-level variable collection: you’ve got the same dilemma twice over. Only some values have changed within the variable, and you have to publish your <span class=”figma-component”>◈ Button</span> as a whole because some of the variables it uses have been altered. This isn’t the end of the world, it just means you have a greater responsibility to write good publication notes for your consumers specifying exactly what changed. Keeping things as separate component variant sets allows your publications to be more granular and only impact designers who are actually using that “flavor” of <span class=”figma-component”>◈ Button</span>.

Luis Ouriach has a great thread that covers about these advantages using a <span class=”figma-component”>◈ Banner</span> as an example.

Now, if you’re not convinced on deprecating your hierarchy variant property, or that you shouldn’t make a variable collection named “❖ Button” with modes for hierarchy, at least consider the following:

For folks who are team-variant-property:

Watch Uber’s Maria Hristoforova‘s fantastic presentation from Config 2023 about API tokens. She explains how we can use the same primitive, semantic, and component levels for organizing design tokens and apply that to how we organize properties. You might consider getting more regimented in this area for better alignment with code. This doesn’t solve the issue of discoverability in places like Figma’s asset panel, but it’s an opportunity to get really thoughtful about the words your system uses, and that’s always a great thing to practice.

A slide from Maria Hristoforova's talk showing 3 different tiers of API tokens.

You also need to be thoughtful about your defaults. You may think it makes most sense to have the <span class=”inline-code”>Primary</span> hierarchy of your <span class=”figma-component”>◈ Button</span> be the default when instances are dropped onto the canvas. But remember, this buries and obscures other options for consumers. Take a look at the production version of your product’s interface (and Figma analytics for instance-insertion) to see which button hierarchies get used the most. It may turn out that <span class=”inline-code”>Primary</span> sees less use than <span class=”inline-code”>Secondary</span>! Remember, the hierarchy level for your <span class=”figma-component”>◈ Button</span> is about guiding users’ actions in the product, not designers’ decisions for what pieces of interface to use. Make it easy for designers to make the best decision decisions, and reduce the work it takes for them to do so.

For folks who are team-variables:

First of all, make sure you don’t need more Modes than what the plan you’re on offers. For example if you have 4 levels of hierarchy and you’re on the Pro or Org plan, then you’ve reached your limit.

Have a plan to re-educate designers about how to switch hierarchy on instances that use Hierarchy. They’ve probably been used to looking around the properties area of the design panel, or are used to swapping components. You’ll need to re-train their muscle memory to head a bit further south and set the mode when they want to change hierarchy.

<h3 id="major-composition-changes">Major composition changes</h3>

E.g. a product card that shows up in many many different contexts.

This is a big one. And like Hierarchy, Major composition changes used to be listed under “things you could use variants OR separate components for.” But I’ve come around. I really think most people, in most cases, should use separate components to manage major composition changes to a component.

What do I mean by “major composition changes”? Imagine you have a product card that displays different information depending on the page its on. The Wirecutter does this with their product cards:

image.png

If you proceed to Wirecutter's Deals page, you'll find products are contained within cards and have a lot more information in them! Here we have detailed explanations about why Wirecutter recommends this particular product, along with the article this product is featured in, and a timestamp of when the deal had dropped.

image.png

Products also get featured in cards in Wirecutter's articles and guides. This is where the card design gets more complicated: there's a blue banner hanging off the top left, and a small beak on the bottom left. The description in the card is shorter here than on the Deals page because the editorial content is handled by the article. Instead, cards on article pages contain more interactive components like buttons and a bookmark icon. The orientation has changed too; the product image sits to the left of the buttons and description instead of above.

image.png

These are all the same component, and there’s a lot of mainstay anatomical pieces such as the product name and image. Because of that you might think it makes sense to make them all variants within a single component named <span class="figma-component">❖ Product card</span> with a property called “on page” with options like “home”, “deals”, and “article”. And you could! But my opinion is that they differ enough in anatomy and visual design I'd probably opt to keep them separate components. I actually decided to build  these components out in Figma myself:

Here's a link to the community file for the Figma file above. The blue ribbon on that "article feature" product card was tough to figure out (I made this before Figma released absolute positioning). But it's up and running!

What about variables?” Well, if I was going to try this... first I’d recommend setting up a collection specific to the component you want to offer major composition changes to. In the case above, it’d be “02 - ❖ Product card.” Again, number of modes will be a big limiting factor. If you need more than 4 compositions, you better be on the enterprise plan. I imagine you’d name your modes the way I mentioned after the context each should be used in: “home”, “deals”, “article.” This is where you might need a lot of boolean variables to show and hide different nested layers. Again, looking at how diverse the layer architecture is for the Wirecutter product cards I built, this could lead you to compromising heavily in this area. Auto layout wrapping can help you a bit with shifting things around, but keep in mind there’s been no mention of variables allowing us to affect auto layout direction.

Ultimately it’s comes down to layer architecture. Variables could be a stronger contender as the feature gets more mature, but right now separate components is the safest decision to default to.

<h3 id="icon-style">Icon style</h3>

E.g. "filled", "stroke"

Previously I listed this under the section about attributes you could use libraries for. I also referred to it simply as “style”, but only talked about icons. I’ve not been able to come up with other kinds of components that could use style in the way I mean it here, so now I’m going to just own it and explicitly say this is about icon styling.

This may feel very specific, but so was the section about hierarchy!

In Bonnie Kate Wolf‘s article “A complete guide to iconography” she says:

"When you have the same icon with variants, here's how I like to handle them...
Filled vs. stroked: If you are using both styles, use a slash after the icon name to indicate filled or stroked icons."
image.png
The same icons drawn in different styles. Source: Wolf’s article

Note that she wrote this piece before Figma released variants, but I still think her advice is solid. The reasons why are similar to the arguments for managing hierarchy:

Keep in mind that once variables can be applied to inputs like stroke, I may shift this section up into the “Always use variables” area. I believe once that happens it will be better to have a “Icon style” collection where you can set up different modes for the same icon... maaaybe.

<h2 id="always-use-component-properties-for">Always use component properties for</h2>

<h3 id="minor-composition-changes">Minor composition changes</h3>

Component properties’ whole deal is about boosting instance usability. They drastically reduce the number of scenarios where users have to deep-click through the layer tree to make modifications to an instance’s composition. Changes such as:

  • Showing and hiding layers
  • Swapping nested instances for other instances (like icons or ✎ content carriers)

<h3 id="configuration-changes">Configuration changes</h3>

Some components compositions—their initial layer structures—remain intact. But how those layers are configured can vary greatly. This is where component properties, specifically the swap property, are incredibly helpful.

For example: a <span class="figma-component">❖ Star rating</span> component will likely always have 5 stars present, but the stars that are "full", "half full", and "empty" depends on the data the designer wants to present. A swap property helps keep the main component's layer count low, and can show her the exact star icon components she needs (no need to go hunting through the library or a sea of icons).

Another great example: Molly Hellmuth encourages folks to use private components (rather than a "status" variant property) for status badges in <span class="figma-component">❖ Avatar</span> components. Nathan Curtis would call <span class="figma-component">.Status</span> a subcomponent). A change in status would be a configuration change: swapping from "active" to "inactive" using a component swap property.

Molly Hellmuth's Avatar component example

And you'll remember that variants are a good fit for this <span class="figma-component">.Status</span> variant set because variants should always be used for binaries. Here we only have two options: active, and inactive. If a third option, like "active with notifications snoozed" was added in, then I would consider handling them as separate components.

<h2 id="always-use-variables-for">Always use variables for</h2>

<h3 id="size">Size</h3>

E.g. Gmail’s “Default”, “Comfortable”, “Compact” for items in your inbox.

E.g. Gmail’s “Default”, “Comfortable”, “Compact” for items in your inbox.

I want to be clear: when I’m talking about “size” I’m talking about how much space that component occupies. I see some folks use “size” when they really mean breakpoint (which you should also use variables for).

Similarly, “size” also gets confused with “device.” And even if you've got your definitions straight, design system experts like Molly Helmuth recommends using px-value breakpoints rather than device sizes:

So how exactly am I defining “size”?

In my view, size means you’re dealing with the same anatomy and composition, but things like padding values and space-between values can change. Size is anything that increases or decreases the component’s height or width, agnostic of contexts like “device” or “breakpoint.”

I think the reason folks confuse size and breakpoint is because they do tend to overlap... the larger version of your <span class="figma-component">◈ Button</span> on a marketing landing page is likely used at larger breakpoints, and the smaller ones at smaller breakpoints... but that won’t always be the case. A complicated web-app with tables and tons of controls might benefit from using <span class="figma-component">◈ Button</span> at it’s smaller sizes to accommodate a denser interface, despite being used at a larger breakpoint.

Luckily you can override an instance’s mode, so when you nest <span class="figma-component">◈ Button</span> inside of <span class="figma-component">◈ Data table cell</span> you can apply different variables to <span class="figma-component">◈ Button</span> that tighten up its padding.

Just as when using variants was the best practice for managing a thing’s “size”, variables allow us to be opinionated within our design system. They expose the values the team agreed to use. It makes making good decisions easy, and because they’re overrideable, designers still can deviate and explore new possibilities.

<h3 id="validation">Validation</h3>

E.g. "default", "success", "error", “warning”

Like with Size, this is where component-level variable collections shine. Keep this collection separate from your other component-level variable collections because not every component in your library need “validation” or “feedback” modes. This will primarily be used for things like form inputs, alerts, and message banners. I would naming this collection “02 Validation component styling”

I recommend naming the first level of groups within this collection after individual components like “❖ Text area” and “❖ Input”. Remember, modes are global within a collection but groups can contain varying and amounts and types of variables. Within a group like “❖ Text area” you may want the following variables (🎨 = color variable):

  • 🎨 Label fill
  • 🎨 Input border
  • 🎨 Input background
  • 🎨 Validation message fill

Then you’d want to set up your modes: default, success, warning, and error. If you’re wondering “how do I account for dark mode!?”, well, if you established theming at the semantic level, then all you need to do is ensure you’re referencing those variables. But if you’re like my team you have to handle theming at the component level (we need to do this because the way individual colors translate between themes isn’t always consistent), and that won’t work here. This means we need to layer different modes from different collections together. Luckily this is something Figma is working on, and they’re calling it “extended collections.” Luis and Jacob briefly talked about this upcoming feature in the “what’s next?” section of their deep dive. Here’s how Jacob described it about it:

Extended collections is going to be one of our answers for solving multi-product, multi-brand approach for variables [...] What we want to do is let you define your base color system, where you have things like “default-bg”, “default-text”, “brand-bg”, and “brand-text.” Then you’d create another collection that’s an extension of the first. You can override variables only to the ones you want to, like “brand-bg” or “brand-text.” [...] This is what allows you to switch between one brand or another.

Handling validation with modes is a big performance win. It can potentially reduce the size of variant sets by 4x! That’s colossal savings for consumers, and from the management end of things.

<h3 id="breakpoint">Breakpoint</h3>

E.g. “1440px and above”, “756px to 1439px”, “755px and below”

I used to couple breakpoint and device, but no more. These are separate things. Breakpoint is all about enhancing component responsiveness at different viewport widths. And if I'm being honest, it's not just about viewport... the folks at ZeroHeight put out a great blog post where they suggest developing a strategy for how you handle responsiveness. Using auto layout on your components and in your mockups helps immensely between major compositional shifts on a screen. But eventually for larger ◈ interface reps  need to also have their compositions altered to fit new spaces. For example, elements that are arranged to sit side-by-side horizontally eventually are so squeezed for space that they need to be arranged in a grid, or vertically:

responsive design.gif
source: Dribble shot by Matt Plays

You should absolutely be using variables and modes to handle breakpoint. I’d encourage you to set up a dedicated collection called “00 - Breakpoint.” You’ll use 2 variables and as many modes as you need for breakpoint ranges. The variables you make will represent the extreme ends of each range. Here’s an example based on Tailwind’s defaults.

  • variable name = min-width mode: sm = 640, mode: md = 768, mode: lg = 1024, mode: xl = 1280, mode: 2xl = 1536
  • variable name = max-width mode: sm = 767, mode: md = 1023, mode: lg = 1279, mode: xl = 1535, mode: 2xl = 999999

And just as they are named, you’ll apply these variables to the min and max width inputs on all your screens’ top-most frame. This will allow you to squash and stretch the screen within those ranges, and flip between modes to see your designs in a different breakpoint. Now, for this to look at slick as the GIF above, you’ll also need to use auto layout wrapping. But that’s a topic for another blog post.

<h3 id="theme">Theme</h3>

E.g. "dark mode"

Previously this was couched under “What about libraries?” Originally a good practice was to take advantage of Figma’s library swapping feature for changing the theme. But that only worked if you wanted your entire file’s theme to be swapped... if you needed to see two themes at once in the same file, you were out of luck.

Enter variables.

If you’re doing true dark-mode/light-mode theming, it makes most sense to set up those modes at the semantic collection level. But as I mentioned earlier, if you’re not consistently swapping your colors, moving your theme modes down to the component collection level might make more sense.

A quick note on what I mean by “true” dark-mode: this is different from “zebra stripe” design. I think this style is on it’s way out, but an example would be having high-contrast sections stacked one on top of the other. It’s tempting to call the variation of components that sit within the dark background sections “dark mode”, but that’d be a misnomer. Brad Frost explains this well in his blog post about dark mode VS inverted colors:

What is actual dark mode? <span class="inline-code">prefers-color-scheme</span> is a CSS media feature that listens to a user’s preference for dark or light mode at an operating system or user agent level ... There’s another thing that sometimes gets called “dark mode”, but really means “this component when rendered on a dark background” ... To ensure components work on a dark background, we’ve established a naming convention called <span class="inline-code">inverted</span>.

<h2 id="libraries">What about libraries?</h2>

The question so far as been "when should you use variants, when should you make separate components, and what about component properties, or variables?", and that's all been in the context of a single Figma library file... but there's a fifth thing to throw into the mix: having multiple separate libraries.

<h3 id="device-OS">Device/Operating system</h3>

E.g. "iPhone" VS "Android", “MacOS” VS “Windows”

This is one that is truly dependent on how you/your team works and what experiences your product offers. Some product organizations have entirely separate teams of designers working on desktop and mobile experiences, and they might maintain separate libraries. Or everyone could be merged together, with all designers expected to mock up, prototype, and spec out experiences across all devices. Netflix's designers warn against structuring your design system on your team structure:

"One trap we should all avoid is coming up with a design system that is shaped around a team, because a team could very well change. Instead a design system should be here to stay." Luca Orio - Schema 2021

Netflix has a presence on a variety of platforms. Its apps need to work on our TVs, on our phones, tablets, and in our browsers. Instead of working out of one big library and handling "device" as a variant property, or even as separate components, they chose (wisely, I think) to handle device at the library level.

Annotated screenshot from the Netflix team's Schema 2021 talk
Annotated screenshot from the Netflix team's Schema 2021 talk

Another choice they made that helps keep the Netflix app experience uniform across those three very different devices is underpinning their device-specific libraries with a library called "Foundations." My understanding of their Foundations library is that it feeds components and styles into their device specific libraries. Overrides might get made to those Foundations components to account for device specific needs (text on the TV is likely much bigger than mobile devices), but this is what helps create that cohesive Netflix experience.

<div class="horizontal-rule"></div>

Phew. Okay... so now what? How do you take this stuff and actually apply it? Well, it'll take some practice and experimentation, especially with those fork-in-the-road decisions. I could tell you to bookmark this post, but this is a 16 minute read! I wrote this to provide in-depth explanations about why certain decisions are sure-fire, and what to consider when you're weighing two or more options. This post is not a quick reference by any means. So I made you one! Below you'll find a flowchart built in FigJam to quickly get the same information in a visual format, right inside Figma.

<p id="free-variants-separate-component-vs-component-properties-flow-chart"></p>

{{free-variants-separate-component-vs-component-properties-flow-chart}}

Between this blog post and that FigJam file you should be able to not only make quick decisions, but strong, accurate ones. After some practice you'll have all the absolutes memorized, and navigating the "this or that" decisions will get easier each time. Especially if you're working with other designers to talk through what's best for you all as a group. And as you're trying out these strategies, tell me how it's going! I'd love to hear what's working, and even more what doesn't work. I intend to follow the same advice myself, and keep this post updated as my thinking evolves.

<h2 id="change-log">Change log</h2>

  • Current version
    Was missing embeds for:
    1) the Figma file showing wirecutter product cards in the section about <a href="#major-composition-changes">major composition changes</a>.
    2) a Molly Hellmuth tweet in the section about <a href="#size">size</a>.
  • August 15, 2023
    Added in configuration changes to "Always use component properties for" section.
  • July 19th, 2023
    Updated to account for variables. Lots of things that were in a section named “things you could use variants or separate components for!” were moved into new sections because of the introduction of variables. I also deleted a section about “resizing rules” which is long dead now that we have min/max width.
    Wayback machine snapshot unavailable.
  • December 7th, 2022
    Updated to account for component properties.
    View a snapshot of this version of this post on Wayback Machine.
  • January 22, 2022
    First publication.
    View a snapshot of this version of this post on Wayback Machine.