Real Estate

How to Build Framer Code Components with AI

We've been building production-grade Framer code components with Claude Code. Not throwaway prototypes, but real components on live client sites, with full property controls that anyone can use without touching the code. By the end of this post you'll understand: - What Framer code components are and why they're worth building - How to prime AI so it writes Framer-ready code on the first try - How to go from a design reference to a working component - How to fix issues and add features in plain English, no code editing required We're going to walk through a real component we built: a CMS-connected property gallery with category filter tabs, a large main preview, a scrollable thumbnail strip on the right, and autoplay. Every prompt, every fix, the whole build.

Ashvin Uday Dige
Design Executive - UI/UX
date logo
July 9, 2026
time
time icon
5 mins

What are Framer code components?

Framer code components are custom React elements that live right on the canvas. They look and behave exactly like native Framer components. You drag, resize, and control them through the properties panel.

What makes them powerful is addPropertyControls, a Framer API that wires your component to the panel UI: color pickers, font controls, toggles, sliders, image fields that connect to CMS. When built right, anyone on your team can customize the component without ever opening the code.

Why use AI to build them?

Most designers never touch code components because the barrier is real. TypeScript, React, framer-motion, Framer's own APIs, all at once. AI removes most of that. You describe what you want, it handles the implementation. You stay in design thinking mode while the code gets written for you.

What you need

A Framer project, access to Claude, and a clear idea (or a reference image) of what you want to build.

Step 1: Prime the AI with a Framer-specific instruction

Start every session with this. It tells Claude the rules of Framer's environment so the output is paste-ready:

"You are an expert Framer developer. Write all components in TypeScript. Always import addPropertyControls and ControlType from "framer". Use framer-motion for all animations. Export a default function component with a typed props interface. End every file with addPropertyControls(ComponentName, {...}). Include @framerSupportedLayoutWidth any and @framerSupportedLayoutHeight auto annotations."

One message, done once. Every component you ask for after this will come out following Framer's conventions.

Step 2: Share your reference and describe what you want

We started by sharing the design image and describing the layout. Claude asked three clarifying questions before building:

  • How should gallery data be configured, CMS or manual?
  • Which category tabs do you need?
  • What should the thumbnail strip do when there are more images than visible slots?

We answered: CMS collection, Exterior / Interior / flexible tabs, and mouse wheel or drag for the strip. That was enough context to kick off the build.

Here's the key part of the initial prompt:

"Build a Framer code component called PropertyGallery. Large main image preview on the left, scrollable thumbnail strip on the right. Category filter tabs at the top. Connect images to CMS. Thumbnail strip should scroll via mouse wheel or drag and auto-scroll to keep the active thumbnail visible. Active thumbnail should scale up with a white border. Smooth fade transition when switching images. Keyboard arrow navigation."

The first version came back fully functional. Tabs, thumbnail strip, CMS binding, fade transitions, keyboard nav, touch drag support, and a fallback state when a tab has no matching content. That's a component that would have taken days to write from scratch, done in one pass.

Step 3: Hit a Framer limitation, and fix it

When we tried connecting the images to CMS, nothing was showing the purple binding dot, the slot that lets you link a prop to a CMS field. We told Claude exactly that: "I can't connect the images to CMS."

Claude identified the issue immediately. ControlType.Array, which the first version used, can't be bound to CMS fields in Framer. The way CMS connection actually works is through individual named props, each showing up as its own bindable slot in the panel.

The fix was rewriting the component with 10 individual image slots (image1 through image10), each as its own ControlType.Image. Back in Framer, every image slot now had the purple dot. Bind each one to your CMS image field, bind the matching category fields, and empty slots get skipped automatically.

This is the kind of Framer-specific knowledge that trips people up. The AI knew the limitation and knew the workaround.

Step 4: Layer in more features

Once the core was working, we added more in a single follow-up message:

"Can we have 20 images total? Put them last in the control panel so they're not in the way. Add scroll isolation so scrolling the thumbnail strip doesn't scroll the whole page. Add clickable arrows above and below the strip to indicate there are more images. Add font controls."

Everything in one go. The component came back with 20 image and category slots pushed to the bottom of the panel, scroll isolation using a native DOM event listener so the wheel event stays inside the strip, up/down arrows that dim at the edges when there's nothing more to scroll to, and five font controls covering family, tab size, weight, letter spacing, and label sizing.

The panel order detail matters more than it sounds. Having 20 image slots sitting at the top of the property panel means you're constantly scrolling past them to reach the controls you actually use. Asking for them to be last is a small thing that makes the component much more pleasant to work with daily.

Step 5: Make it respond to its container

The component was responsive but it was responding to its own internal logic, not the Framer frame it was placed inside. If you resized the frame, the component didn't adapt. We asked for it simply: "The component should be responsive according to the container it's in, it should fill whatever Framer frame it sits inside."

Claude rewrote the root div to width: 100%, height: 100% and added a ResizeObserver that watches the actual rendered container and updates internal sizing state in real time. All internal scaling, tab padding, offsets, font sizes, derives from those live pixel values. Drop the component on the canvas, resize the frame, everything inside adapts. The fixed width and height props were removed entirely.

Step 6: Add autoplay

The last piece: images should cycle automatically. We described the behavior we wanted:

"The images should automatically change. The timer should reset when someone manually clicks a thumbnail or switches tabs. It should pause when hovering. Both behaviors should be individual toggles in the panel."

Claude added a timerSeed state variable, a small but important detail. Rather than just using a setInterval directly, bumping timerSeed on each manual click forces the interval to restart from zero, so the next auto-advance never fires immediately after a manual pick. It feels natural. isHovered state handles the pause. Three new panel controls, Auto Play, Interval (0.5s to 30s), and Pause on Hover, appear in the panel with the latter two hidden when autoplay is off.

What made this build go smoothly

Looking back at the whole session, a few things consistently produced clean output.

Describe what you see, not what you think the code should do. When the CMS connection wasn't working, we said "I can't connect the images to CMS" not "the ControlType is wrong." When the strip was scrolling the page, we said "scrolling the preview scrolls the whole page" not "stop event propagation." The AI handles the translation.

Ask for panel order deliberately. The order you specify for property controls is the order designers and clients see them. Putting images last, grouping fonts together, hiding irrelevant controls, these make a component feel considered.

One message per feature cluster is fine. Step 4 bundled four changes into one message and that's not a problem as long as each one is described clearly. You don't need a separate conversation for each tweak.

Use clarifying questions as a feature, not a delay. The initial questions about CMS, tabs, and scroll behavior meant the first output actually matched what we needed instead of requiring a rebuild.

Wrapping up

The biggest shift isn't speed, even though it's much faster. It's scope, what you're willing to put on a proposal. A component like this, with CMS binding, category filtering, scroll isolation, responsive container sizing, and autoplay, would have meant bringing in a developer. Now it's part of the design work.

The question changes from "can I build this?" to "can I describe this clearly enough?" That's already a skill you have.

Start with something small. A scroll reveal, a ticker, a hover effect. Get the loop into muscle memory and then go build the thing you kept talking yourself out of.

Made with Claude. Shipped in Framer.

Book your free consulation

Share

linkedin iconfacebook logox linkcopy link
Ashvin Uday Dige
Design Executive - UI/UX

Ashvin creates clean and user friendly digital experiences through thoughtful UI and UX design. His work focuses on making design both functional and visually engaging.

Tags

UX and UI Design
Website Design and Development