Sometimes when you’re making a component that uses many nested instances within it and you know it will have many variables (into the thousands), it becomes daunting to think about the possibility of getting something wrong. You don’t want to put in all the work of creating hundreds and hundreds of variants only to realize you’ve forgotten something, or should’ve approached one piece of the component differently, such as componentizing text alignment in your buttons.
On the flip side, there’s also concern about over-engineering what ought to be a simple object. We know that the more layers you have in a file, the more memory it consumes, and that can lead to sub-par file performance. Plus, when it comes to things like text alignment, color, corner radius, and auto-layout resizing rules, those things can still be manipulated as overrides within component instances... do the benefits of controlling those things as variants outweigh the cost of all the layers that need to be created to support them? There is a tension between building components that are robust and layer-efficient.
But are there clear circumstances when it’s better to create variants which adjust characteristics that can be handled by overrides? Or times when it’s more appropriate to have fewer variants and encourage component users to use overrides to adjust things?
There is no blanket best-practice answer for this because these questions aren’t actually about best practices for working in Figma, but rather questions about how you and your team will use the components. It comes down to control, comfort in Figma, where you prefer to put in work, and trust. Those things will look different for every person and every team. Let’s explore the tradeoffs of componentizing characteristics that can also be handled by overrides:
Buttons, once again, are a great example. Sometimes your buttons need to hug the text and icons contained within them: the contents of the button dictate the button’s overall width. Other times you want your buttons to fill all available horizontal space. Perhaps you know that the majority of the time you want our buttons to be set to “hug,” so you build your button component with that resizing setting. Then when you grab an instance and the time comes where you need that button to fill all available horizontal space, you can override that resizing rule. Here are the tradeoffs being made:
Hopefully you’re picking up on a theme with those tradeoffs, especially with the last three: there is slightly more work to be done by the component user to adjust the component than if the resizing rules were handled as a variant property of the button component. A button component is likely to have variant properties that control things like state and hierarchy; the existence of these variants tell component users, “these are the options available for use,” which both saves them time and gives them confidence that they’re using the component as intended. On the component management side of things, variants offer more visibility to how complex any single component is. With variants, you can see every possible permutation in a component, and literally zoom in on it and make sure it’s built properly and matches its neighbors.
Overrides, however, can’t be managed the way that variants can, and therefore introduce risk. By its nature, an override is a deviation from the main component, but they're also necessary in design work! For example, overriding the text of a button is a natural part of working with that component and should absolutely be expected to happen. Overrides to text are also one of the easier overrides to keep track of. If the default text in your button component is “button”, and someone overrides it to say “Save changes”, then you can know just by glancing at the object, that an override has been made. But for other overrides, like colors and effects, and even more so, resizing rules, it can be harder to keep track of not only if an override was made but at which layer... For more complex components made up of many nested instances and objects, it becomes incredibly difficult to tell if any overrides have been made, and where they were made. The only way to find out is by right-clicking on the object and seeing if “reset overrides” is a menu option. Even then, Figma doesn’t tell us what overrides we’re resetting. The best you can do is reset it, and hope you notice a visual change. If you’re stumped at least you can undo things!
I’ve searched Figma’s community plugins to see if anyone has made something that adds some indicator of where overrides have been made to a component, but so far no luck. This is actually a rare moment where I think back to using Sketch and miss something; in Sketch, component overrides are abstracted away from the actual object and exist as inputs in the design panel. When you select an instance you can scan the available overrides and see which ones have been modified. Though I don’t believe there’s a way to selectively reset overrides in Sketch, you may be forced to reset all of them just like in Figma. Tradeoffs strike again!
So if there’s no blanket best-practice to follow, what are we to do? Because of the number of tradeoffs at play, I decided to make an interactive quiz built in Figma to help folks decide how to approach the architecture of their components. While you could use this quiz with your entire component library in mind, I'd also recommend narrowing your view to a single component or closely related group of components (such as form elements). You may find mixed-methods approach may serve your component library well! The quiz is just 5 short questions. All you have to do is select the grey box in each section titled "SUBMIT YOUR ANSWER" and use its variants to submit your answer. At the end of the quiz you'll get to review how you responded to each question, and then based on which colorful icon you have a majority of you can reveal your guidance for how to approach the build of your components.
Once you take the quiz and explore the guidance, tell me if you find it useful! I'd love to know how it can be improved (I already have some plans to follow up with more detailed journal entries on what using these three different methods looks like).