3 reasons to use variables for validation styling (instead of variants)

When folks show off the power of variables, they usually talk about breakpoint or color theming. Those each work well as demo use cases because they often showcase dramatic shifts from one mode to the next.

But those aren't the only things variables are good for. A less sexy, but just as valuable, use case for variables is validation styling for form elements.

Before variables I would’ve used a variant property to handle these four different validation states:

  • Default
  • Success
  • Warning
  • Error
Screenshot 2024-05-09 at 6.53.42 PM.png

But it came at the cost of increasing the variant count of those components by 4x! That's pretty expensive if you ask me. For the <span class="figma-component">❖ Text input</span> example above, each instance costs 59 layers. More variants means more layers, and more layers means more memory gets used.

Screenshot 2024-05-09 at 6.54.19 PM.png

And those 59 layers are before I add in any other properties:

  • Interactive state styling (variant selector)
    • Default
    • Hover
  • Enabled / disabled (variant boolean)
  • Populated / empty (variant boolean)
  • A focus ring (component prop boolean)
  • Text or asterisk to signal required fields (component property boolean)

After all that gets added in, the count will be well over 150 for every single text input. And text inputs are probably the lightest of the form elements! Imagine something like a date picker? Yikes.

In my experience, designers aren't frequently reaching for validation styling in their mockups and prototypes. Having a property that doesn’t get uses violates one of my rules for making excellent components. Bogging down the design panel with properties that aren't being used creates visual clutter at best, confusion at worst.

But just because designers don’t use that validation styling in their mockups, that doesn’t mean those styles shouldn't be defined. Validation is really important after all!

So we’re faced with a tradeoff: include the validation variant prop that will weigh down the component and go unused by designers, or only account for it in our documentation and hope a designer never needs to mock something up with validation styling?

Before variables, I went with the first one. It's expensive, but safe. And I’m a safety-first kinda gal.

But when variables came out I was THRILLED! Finally I could get the best of both worlds:

  • Reduce the size of the variant set, offering a more performant component for design library consumers
  • Provide even better validation styling to the design system engineer (because I could alias color variables, something color styles couldn't do)!

And now I’ll tell you how, both for single-color theme products and products that have multiple color themes (like light and dark mode; you can jump ahead to that section):

How to set up validation variables for a single color-theme product:

If you don't have color theming (eg light and dark modes), setting up your validation variables is pretty straightforward. You could follow along this blog post and copy from my screenshots by hand, or purchase a demo .fig file I’ve set up for you!

Here's the instructions:

  1. Create a collection named “02 validation.” The 02 prefix means this is a component level collection. If you don't know what I mean by that, read this short blog post I wrote about collection levels.
  2. Set up 4 modes in this collection (the order of the modes after Default does not matter, but Default should definitely be first):
    1. Default
    2. Error
    3. Warning
    4. Success
  3. Begin creating color variables to house your validation styling. How you name these and how many you make is a topic for another blog post, but you’ll need something to color all the elements that make up your form fields: the label, the input, validation messages, helper text, icons, etc.
  4. Use aliasing to reference colors in your primitive level collection. For example, green 100 on your “background” color variable in success mode.

Here’s a visual example for one way I’d set up this collection. Again your variable names and how many variables you need may be different from this:

image.png

And here’s how the 4 different modes look side by side:

image.png

There’s a few things I want to point out about this set up:

  • This example shows a pretty basic and common input field. You’d likely need more variables for more complex inputs. Think date pickers and range sliders.
  • Any interactive state styling is also accounted for in this collection, such as <span class="figma-variable">background:hover</span>. Those get applied to variants in the component set with the corresponding interactive state.
  • Notice how I chose to make the border color, input value color, icon color, and validation message color all dependent on the same variable called “foreground.” I did this for two reasons:
    • 1) I knew I would reference all the same primitive colors across them anyway, and
    • 2) I know that if I ever want to split them up, it’s easy to do. This doesn’t mean you should always collapse variables together that have the same values across modes, but when you see that happen, it never hurts to pause and ponder the idea.
  • Validation messages get their own unique icons. Success has a check, Warning has a triangle exclamation point, and Error has a box with an “X” in it. These icons are nested in the main component, and their visibility is controlled by individual boolean variables. This is the most efficient way to set this up if my icons are instances. If I was using an icon font (which I wouldn’t, I think they’re far too difficult to use), I would use a single boolean variable and a string.
  • Notice that all these variable values, except for the booleans, are aliasing another variable! Again, I’m using two different levels of collections: a collection of primitive variables to store all the raw color values, and a component level collection for validation styling.

Once your variables are set up it's just a matter of applying them to your main component!

<h2 id="validation-with-color-theme">How to set up a validation collection for a product with multiple color themes</h2>

If I'm dealing with light and dark mode, or modes for unique brands, things get more complicated.

To successfully incorporate a validation collection, I'll need to weave the color theme collection and the validation collection together. The end result should allow me to plop an instance of <span class="figma-component">❖ Text input</span> on the canvas, independently control the color theme and validation styling. Like this:

validation dark mode.gif

Today, setting up the variables to make this possible is a bit tedious. Luckily, Figma is already on the case. Back at Config ‘23 when variables were announced, they also gave us a sneak peak about a future enhancement called extended collections. Once that’s released, we can use it to make this “threading” of collections much more manageable.

But for until that happens, here’s how I’d make do:

For every variable in your “02 Validation” collection, make a matching variable in your “01 Color themes” collection. Then put those repeated variables in a group named after each of your validation modes:

image.png

This allows you to declare what you want “success” to look like in light and dark mode, and so on with the other validation modes.

Once you have all those set up, you can go back to “02 Validation” and alias in the variables you just made in “01 Color themes”:

image.png

Once that’s hooked up, you’ll apply the “02 Validation” collections’ variables to your form element components. Because “02 Validation” is consuming aliased variables from “01 Color themes”, you get access to all 6 modes: light, dark, default, success, warning, and error. Check it out:

validation dark mode.gif

And what does all that effort save you in layers? A lot. We went from 59 to 13. That’s an 88% reduction in size!

Screenshot 2024-05-09 at 8.30.15 PM.png

Besides saving tons of file memory, this also keeps the design panel clean. Relevant properties that designers actually use will won’t be crowded out by properties they won’t ever touch.

Plus, if they need validation styling, they still have it! Only difference is now it’s a mode, not a property.

And now that setting a variable mode is now a triggerable action, designers who do need to show validation feedback in their prototypes can set up validation criteria! Imagine an interaction that reads like this:

<span class="inline-code">On click</span> (of a button at the end of a form), if the <span class="figma-component">◇ input</span> instance is <span class="inline-code">empty</span>, set the <span class="figma-component">◇ input</span> instance’s mode to <span class="figma-variable">error</span> and update its <span class="figma-variable">validation text</span> layer to read “this field cannot be left blank”, else <span class="inline-code">navigate</span> to the next screen.

If you try out a validation collection, let me know how it goes and what you learn!

Want edit access to the Figma file (and those 3 variable collections) I used to make these screenshots? For a couple bucks you can buy a copy! This can be a great learning tool to snoop around and explore first-hand how everything is set up.

<a href="https://alicepackard.ck.page/products/validation-variable-collection-starter-file" class="button primary" style="padding:16px,0px; margin:auto; border-bottom:0px solid">Buy the .fig validation variable collection file</a>