Crafting Interactive UI Components in Framer
Applying State Management through Code Overrides
Introduction
I recently published a side project, I wanted to dive deep into color accessibility so I assigned myself the task of creating a simple data visualization component to learn more about it. I imagined several categories to make a significant use of color in them. Soon I realized that in order to achieve the multiple iterations I’ll need to make use of code.
While I learned a ton about color accessibility I’ll save that topic for another article. Here, I’ll focus on the component structure, the strategic use of code overrides in Framer, and the implementation of React’s useStore
concept to achieve the interaction that I envisioned.
Component Structure and Composability
One of Framer’s strengths lies in its flexibility to create and manage components. You can approach it visually or leverage code, or even combine both. Since my strength lies in design, I prioritize the visual interface whenever possible. However, my ambitions for this component exceeded what could be achieved purely visually in a way that remained simple and easy to iterate in the future so I took advantage of this flexibility and did both.
First, I created the Chart component and nested the two smaller components where I applied the color: a Tag component and a LineChart component. Both were designed visually, similar to how you would work in tools like Figma.
- The Tag component has inactive, hover, and active states. It is defined generically and also, at this level is where I tackled the animation for the appearing ‘x’ icon button. Then I deliberately assigned four variables that will allow me more specific application of the color at the higher level, in the complete Chart component.
- The LineCharthart component, on the other hand, demanded a different approach due to its need for independent visualization. Each line chart instance is independent and operates separately.
Why and when to use code overrides
In my project, I needed the component to update the related LineChart whenever the user clicked a Tag. Visually managing all the possible permutations through variants would have been impossible. Here’s where Code Overrides came into play.
Code overrides in Framer are custom code snippets that allow you to extend and modify the behavior of components beyond what is possible with the visual interface alone. You write the code in a code editor and then apply it to a layer to enhance its capabilities.
To efficiently manage state across components, I integrated the useStore
hook provided by Framer’s store library into the project. This custom hook allows components to access and potentially update shared state across the UI. I’ll explain this function in detail in the next section
useStore function
To efficiently manage state across components, I integrated the useStore
hook provided by Framer’s store library into the project. This custom hook allows components to access and potentially update shared state across the UI. The createStore
function from Framer’s store library is used to create a store with a defined initial state activeTags: [ ]
. The useStore hook then allows components to access and update this state.
In this case, it facilitated communication between the tag and line chart components. It basically means that when the tag is clicked, the line chart is shown, and vice versa.
Here’s how a simplified version of the code looks:
import type { ComponentType } from "react"
import { createStore } from "<https://framer.com/m/framer/store.js@^1.0.0>"
const useStore = createStore({
activeTags: [],
})
export function withActiveTag(Component: ComponentType<any>): ComponentType<any> {
return (props: any) => {
const [store, setStore] = useStore()
const isActive = store.activeTags.includes(props.label)
export function withLineChartFiltering(Component): ComponentType<any> {
return (props: any) => {
const [store] = useStore()
const isActive = store.activeTags.includes(props.label) // Check if the label is in activeTags
}
- Store Creation: createStore initializes the store with an initial state, activeTags.
- withActiveTag HOC: This higher-order component (HOC) wraps a component, providing it with isActive state and onClick handler. The onClick handler updates the store based on whether the tag is active.
- withLineChartFiltering HOC: This HOC wraps a component to filter the LineChart based on the active tags, ensuring the LineChart updates when a Tag is clicked.
Issues
It’s important to be mindful of potential conflicts between code and parts defined through Framer’s visual interface. Pay close attention to how variants, variables, and naming conventions interact to avoid unintended consequences. Additionally, unforeseen conflicts can arise if both approaches try to manage the same functionality.
For example, I visually linked tag’s inactive/active states for user clicks. However, code overrides also controlled state. This caused mismatches leading to inconsistencies between the tag component and the line chart.
Conclusion
While I still have much to learn about code, these little wins feels so rewarding. Framer offers an excellent opportunity to understand how React works by observing tangible results.
I’m excited to craft more prototypes that feel like the finished product. This approach allows me to see outcomes beyond my design skills, with coding learnings that are incremental enough to keep me engaged and not want to quit. It’s a step ahead to understand better the web, the medium where product designers must ultimately ship their work.