Writing Better (and Worse) Code in Framer
Rookie code mistakes (and how you can avoid them).
I’ve been spending some free time haunting the Framer group on Facebook, using the questions posted as a way to learn more about how Framer works. One of the most common questions posted to the group goes like this:
I have a row of five layers. When you click a layer, it turns ‘on’. When you click it again, it turns ‘off’. How do I make it so that only one layer can be ‘on’ at a given time?
The question breaks down to three components:
- Add a click event to a layer to turn it on in some way.
- Add logic after that click event to turn the layer off if it is on.
- Add logic after that click event to turn off any other layers.
A pretty simple ask, but solving it requires just the right amount of complexity to create problems for designers new to Framer or code or both. (By the way, if you don’t have Framer yet, download a free 2 week trial). I’ll use this question to look not only at how to turn layers on and off, but how to think about the code we write, and then how to write it better.
But first, here are two ways to solve the question. On the left is the bad way. On the right is the better way. We’ll get into both and see why the one on the right is better.




How to do it the bad way.
Let’s say we’ve discovered that Framer makes it easy to change how a layer looks and have mastered the basics. In approaching the design problem described above, we’ve decided that we’ll change the color of a layer to define its state, use yellow for on and green for off.
Let’s say we have an array of layers (neatly defined in the examples below as arrayOfLayers), and we’re defining what they should look like and how they should work. Here’s the simplest way for us to turn a layer on.


We’ll also need to turn it off if it’s on when we click it. Since we’re using background colors to indicate whether a layer is on or off, we’ll add some logic to the click event that will decide what color to make the layer by using the layer’s existing backgroundColor value.


Not very pretty, but it works. Notice that we’ve had to drill into @backgroundColor.color to get the name of the color. It wouldn’t have worked otherwise. But hey, we’re making progress.
So how do we turn off any other on layers too? We’ll need to add some extra code to each layer’s click event so that, when we click on the layer to turn it on, it will also go through all the other layers in its array and turn them off if they on.


And that’s it! All three components satisfied: clicking a layer will turn it on if it was off, will turn it off if it was on, and will turn off any other on layers before turning this one on. Our code is a bit of a mess, but at least it’s a mess that works.


What was so wrong with that?
First and foremost, in the above example we were using an unstated abstraction. While we knew that ‘green means off and yellow means on’, this abstraction isn’t really stated anywhere in our code and anyone who looked at the code would spend the first minute or two wondering why we are changing so many colors. Even if our project is private, working this way forces us to constantly do the work of abstracting ‘a layer is green’ to ‘a layer is on’ as we read it. If our code is difficult to read at this extremely simple level, you can just imagine how things will look when we’ve made things more complex.
We’re also blending logic, manipulation, and interaction in the layer’s click event function. When we click a layer (interaction), that interaction runs a function that decides what layer to change (logic) and makes changes to that layer (manipulation). We should really try to keep these three things separate, so that our interactions point to a separate function for making decisions, which might in turn point to another function for executing actions. When we do, we’ll be able to make changes to either of the three without affecting the other. We’ll also be able to perform actions from different event sources without having to rewrite everything.
And of course, we’re using a visual property to pull double duty as data. Even if we and our users understand that yellow layers are on and green layers are off, in the code green should just mean green. Framer and CoffeeScript give us several really good ways to store information. These will not only let us store data in clear ways, but also let us work with that data in clever ways. We should take advantage.
Now here’s how to do it better.
We’ll begin with data. The first thing we’ll do is give a property to each of our layers called isOn that will store our abstraction (on or off) as a boolean, meaning that it will store either true or false. If layerA.isOn = true, we’ll know that layerA is on. More importantly, our code will be able to use this data too.


We want to manipulate this property with some logic, but it’s important to separate those two things out. It’s also important that the layer itself is responsible for making changes to its own property, so we’ll give our layer two methods to handle this: turnOn() will set that layer’s isOn value to true, and turnOff() to set it to false.


turnOn() and turnOff() methods will make changes to the layer’s isOn property.Now to our logic. We want a way to toggle between turnon() or turnOff() depending on whether a layer is on or off. We’ll do this with a third method called flipSwitch(). For now, all flipSwitch() will do is check the value of this layer’s isOn property and trigger either turnOn() or turnOff() to reverse it.


Next we’ll add our interaction to trigger this change. We’ll add our click event and tell it to run the layer’s flipSwitch() method.


Technically, we’ve just satisfied component 1 and 2 of our problem. We have a layer, we can turn it on if it’s off, and we can turn it off if it’s on. Obviously something is a little lacking, because we still can’t see which layers are on or off. We’ll get to that soon; however, while we’re still working on logic, let’s add some extra code to flipSwitch() to satisfy our problem’s third component of our event, which was to first turn off any other other layers that might be on.


Let’s check in on where we’re at here. When we click on a layer, it triggers that layer’s flipSwitch method, which reverses that layer’s isOn value, then looks through arrayOfLayers for any layers that aren’t the layer we clicked on and have isOn = true, and it turns those layers off.
Things are working, but how can we check? Since we haven’t represented the changes to on or off visually, we can take a shortcut by adding one more line of code to flipSwitch() that will display the value of each layer’s isOn as a label on top of that layer.


If you’re playing along at home, you should now be able to see that everything is working. Once you click on a layer, all the layers in arrayOfLayers will display their isOn value. If you click a layer, it will read true of it was false, or false if it was true; and clicking on a different layer will turn any other true layer false.


Our last step is another piece of manipulation. This time, instead of changing a layer’s data property, we want to change a layer’s visual properties to reflect the value of that data.
We have several options here. We could add an extra line of code to both turnOn() and turnOff() that would also change how the layer looks. While that would work for our current project, we would be sneakily blending logic and manipulation, by expressing the statement if isOn() is true then turnOn() without actually stating it. We could be setting ourselves up for a very tricky bug later on.
A better option would be to give each layer two more methods called showOn() and showOff(). The first will describe how we want to display an on layer, and the second will describe how we want to display an off layer. By keeping them separate, we can go on to make their logical relationships to isOn more explicit.


We have our data, we have our logic, and we have our manipulation. Let’s bring it all together.
We’ll make a new function called updateLayers() that will be responsible for triggering display changes in response to data. It will run through the layers stored in arrayOfLayers(), check each layer’s isOn property, and tell that layer to showOn() if isOn = true or showOff() if isOn = false.
This function will need to run any time we make changes to theisOn properties of our layers, so that our project displays those changes visually, so we’ll put it in two places. First, we’ll add it to our click event, so that it reflects any change that occurred after we clicked on a layer. Second, we’ll put it at the bottom of our code, so that it will run when the project first loads. Since we’ve set our layers’ isOn properties to false by default, running updateLayers() will respond by running turnOff() on all of our layers.


And we’re done! Since the testing is complete, we’ve taken out the line in flipSwitch() that displayed the isOn labels.


Recap — or why was this so much better?
Why make so many functions and methods when we could, as in the bad example, have dumped everything into the click event? After all, our bad example worked, and worked with only two functions and twenty lines of code, and our good example has nine functions and thirty-four lines. Here are some reasons why that added length might be worth the effort.
- In our good example, we’ve separated manipulation and logic, building the project in such a way that how we display on or off has nothing to do with how our project works; we could change the display completely and not have to worry about breaking the project’s logic.
- Since
turnOn()andturnOff()are separate methods, we can easily change the manipulation that occurs when we turn a layer on or off by adding code to those methods. If we wanted text to appear when we turned a layer on, then disappear when we turned a layer off, we could easily make those changes without stepping on any other functionality. - We can easily extend the logic without touching any other code. If we wanted to have two items be on at a given time, we could add that logic into
flipSwitch(). We could even give our layers some other boolean property, likeisReady, and add it into the decisionflipSwitch()makes about which layers to turn on, or add a line inupdateLayers()that will grey out any layer that has atruevalue forisReady. The structure we’ve built would let us plug in those changes. - Perhaps most importantly, our code is readable and self commenting. Our creation, data, logic, manipulation, and interaction are kept separate. Our methods and functions are clear, limited by kind, and named with self-explanatory titles. Our abstractions are kept consistent throughout the project — we didn’t, for example, switch from on and off to active and default halfway through. As a result, we could hand this project off, even without any code comments, and be fairly certain that whoever picks it up will quickly see what each event is triggering, in what order things are happening, how we’re making decisions and which code is doing what to what.
If you found this post useful, let me know. This was a general topic (and a long article), but I thought the Framer community could use it. I’ll get into more specific common problems in the future.





