Guest Post
Bringing Prototypes to Life With Data
How to design with Randomized Data, Real Data, APIs, and more in Framer X.
Max is a product designer at Zoom in San Francisco passionate about design systems, prototyping, React, and creating delightful user experiences. His guide for transitioning from Framer Classic to Framer X has helped many make the switch and he is also the creator of the very popular Resizable Window component available in the Store.
Designing with data helps build a connection to the people who use your product every day. Let’s walk through how to make that possible.
Props
If you’re just getting started with React, one of the key concepts to grasp are props. A prop is short for property, and works just like the right-hand properties panel you’re used to adjusting in Framer X. In design tools, we can modify the background color with a color picker, the opacity with a slider, and the radius with an input. In React, we can “pass in” props to modify just as easily.
Visualizing props
Building React components is a lot like design components created in the canvas. After creation, Framer automatically recognizes elements you may want to change. In the design component below, the avatar, name, and message can be changed.

When working with code components, things start to look familiar…
<Message Avatar={"./images/Headshot.jpg"} Message={"Hey everyone!"}/>
As you can see, using data in our prototypes is as simple as passing in props. You can learn more about props in this article from Koen Bok. Here are a few ways to get started working with data in Framer X.
Randomized Data
One of the easiest ways to start playing with data is to create your own. Like all designers, you probably have a list of go-to placeholders. Using randomized data is a great way to give your prototype a fresh look on each reload. All it takes is a simple function that accepts an array, then randomly returns one of the values.
function random(list: Array<any>) { return list[Math.floor(Math.random() * list.length)]} const names = ['Johnny Appleseed', 'Sarah Brown', 'Koen Bok', ...] console.log(random(names)) //Koen Bokconsole.log(random(names)) //Johnny Appleseedconsole.log(random(names)) //Sarah Brown
Plugging that into our React component would look something like this:
<Message Avatar={random(images)} Name={random(names)} Message={random(messages)}/>
JSON
Chances are there’s JSON data lying around that you can use within your designs. This method helps reflect real use cases and demonstrate what the product actually looks like. This also works as a great way to quickly edit what’s displayed because the file is editable.
import * as data from "./Test.json"import { Message } from "./Message" export function ChatFeed() { let messages = data.map((item) => ( <Message name={item.name} text={item.text} image={item.image} /> )) return ( <Frame> {messages} </Frame> )}
First, we’ll need to import our JSON data. Shown on line 1, we can import * as data
, which is short for import “everything” as data from the file. You could choose any name, but I went with data to help keep track of what I'm handling within the component.
Next, we’re going to make use of the map
function, which is a lot like a forEach
loop—only better. The map function is a declarative way to loop over each item in an array, and in this case, each piece of data in our JSON. It creates a new array for us (as React doesn’t allow mutating), which we can assign to a variable called messages
that will be used in the return function.

APIs
Taking things a step further, we can grab data directly from the source. We can use APIs that return data for us, typically in the form of JSON.
What’s an API?
Don’t worry, I didn’t know much about them either before using Framer X. You might compare them to ordering food at a restaurant. Just like you order what you’d like from the menu, using an API is a way to order things. We’ve been using a chat message component so far, so something we might want to order from an API is avatar images. For this example, tinyfac.es delivers those images to you.

export function Avatar() { const [image, setImage] = React.useState("") React.useEffect(() => { const url = `https://tinyfac.es/api/users` fetch(url) .then(response => response.json()) .then(data => setImage(data[0]["avatars"][3]["url"])) }, []) return ( <Frame image={`url(${image})`} /> )}
For this one, we’re using both the useState and useEffect hook. If you aren’t too familiar with these, Zach Johnston gives a great overview in this Framer blog post.
After we define our URL (https://tinyfac.es/api/users), we can “fetch” the data from the API, then wait for the data to be served, then set our image state using that same data. That’s all it takes to get started using an API within your components.
Database (Firebase)
So many of our products have a collaboration aspect that it can be difficult to simulate what a “real” experience would be like. Firebase can do just that, giving prototypes the power to talk to one another.
Getting Started
Setup in Firebase
- Head over to https://firebase.google.com and create a project.
- Go to Settings → Project Settings. In the General tab, look for “Your apps”, and select Web from the options of iOS, Android, Web, and Unity.
- Give your app a nickname and check the box that reads: “Also set up Firebase Hosting for this app.”
- Skip the rest—you’re all set up.
- Returning to Settings, scroll down to “Your apps” and select the Config option. You’ll be needing this in a bit.
- On the left panel within the Develop section, click Database → Create Database. Choose “Start in test mode”.
- Use the dropdown to go to Realtime Database, then go to rules and change both read and write to
true
.
Setup in Framer X
- Create a new Framer X file and name it FirebaseFramerX.
- With the file opened, go to File → Show Project Folder.
- Open Terminal and enter
~ $ cd FirebaseFramerX.framerx
. - Next, enter
npm install firebase
. - Create a new code component and name it ChatFeed.
- Copy and paste the snippet below, replacing firebaseConfig with your own from step 5 in the section above.
import * as React from "react"import { Frame, Stack } from "framer"import * as firebase from "firebase" let databaseconst firebaseConfig = { apiKey: "YOUR_API_KEY", authDomain: "project-name.firebaseapp.com", databaseURL: "https://project-name.firebaseio.com", projectId: "project-name", storageBucket: "", messagingSenderId: "xxxxxxxxxxxx", appId: "x:xxxxxxxxxxxx:web:xxxxxxxxxxx",} const LoadFirebase = () => { if (!firebase.apps.length) { firebase.initializeApp(firebaseConfig) } database = firebase.database()} export function ChatFeed() { LoadFirebase() const [messages, setMessages] = React.useState([]) React.useEffect(() => { let firebaseDatabase = firebase.database().ref("messages/") firebaseDatabase.on("value", snapshot => { let newMessages = [] snapshot.forEach(child => { const message = child.val() newMessages.push( <Message key={child.key} name={message.name} text={message.text} /> ) }) setMessages(newMessages) }) }, []) const writeMessageToFirebase = value => { firebase .database() .ref("messages/") .push({ text: value, name: "Max", }) } return ( <Stack size={"100%"}> <Frame onTap={() => writeMessageToFirebase("Hello")}> Send Message </Frame> {messages} </Stack> )} function Message(props) { return ( <div> <div>{props.name}</div> <div>{props.text}</div> </div> )}
Breaking this down, there are 3 main concepts to grasp.
Setup (lines 1-24): Getting hooked up to our database.
Listening for changes (lines 26-44): Once a message gets sent, our component will re-render with the updated state of the database.
Pushing changes (lines 46-54): The writeMessageToFirebase
function allows us to send messages to the database that will be reflected in all prototypes.
What’s next?
These are some of the tricks that have helped push my prototypes to the next level. Now that you’ve learned how to get started working with data, jump into Framer X and bring your prototypes to life. Feel free to reach out on Twitter and ask questions.
Or dive into some more learning resources:
Bring your best ideas to life
Subscribe to get fresh prototyping stories, tips, and resources delivered straight to your inbox.