Component Trees,
fully labeled.
Every Smart Component, Canvas Component, and CMS-bound element gets mapped to its React equivalent — props typed, variants enumerated, overrides flagged.
Read the Full Spec Online →| Component | Type | Props | Variants | Overrides | Framer API Used |
|---|---|---|---|---|---|
| NavBar | Smart | 12 | 4 | yes | useScroll · useMotionValue |
| HeroBlock | Canvas | 8 | 6 | yes | motion.div · AnimatePresence |
| CardGrid | CMS | 6 | 2 | no | useCMS · framer-motion |
| Modal | Smart | 9 | 3 | yes | useAnimation · Variants |
| RichText | Static | 4 | 1 | no | none |
| FormBlock | Smart | 11 | 2 | yes | useForm (internal) |
// NavBar.framer.tsx — DO NOT EDIT
import { motion } from "framer-motion";
import { useScroll } from "framer";
import { addPropertyControls } from "framer";
export function NavBar(props) {
const { scrollYProgress } = useScroll()
// 847 lines of generated code...
addPropertyControls(NavBar, {
_id: { type: ControlType.String },
__framer_: { type: ControlType.String },
})
}// NavBar.tsx — portable, typed
import { useState } from "react";
import { useForm } from 'react-hook-form';
interface NavBarProps {
logo: string
links: NavLink[]
sticky?: boolean
theme?: "light" | "dark"
}
export function NavBar({
logo, links, sticky = true, theme
}: NavBarProps) {
const [scrolled, setScrolled] = useState(false)
// 42 lines of clean code
}State machines,
not black boxes.
Every Framer interaction is a hidden state machine. The CLI surfaces triggers, targets, state variables, and the exact handler signatures — ready to drop into React, Vue, or vanilla JS.
Read the Full Spec Online →| Trigger | Target | Action | State Variable | Handler Name |
|---|---|---|---|---|
| onClick | Modal | open | isOpen | handleModalOpen |
| onHover | CardGrid | scale(1.04) | hoveredId | handleCardHover |
| onScroll | NavBar | bg-opacity | scrollY | useScrollEffect |
| onTap | Accordion | expand | openIndex | handleAccordion |
| onDragEnd | Carousel | snap | activeSlide | handleDragSnap |
| onAnimComplete | HeroBlock | unlock CTA | heroPlayed | onAnimationComplete |
// Framer internal state binding
const [variant, setVariant] =
useVariantState({
component: "NavBar",
defaultVariant: "Default",
enabledGestures: {
Default: ["hover", "tap"]
}
})
// Opaque. Non-transferable.// Clean state — any framework const [isHovered, setIsHovered] = useState(false) const [isTapped, setIsTapped] = useState(false) // Typed. Documented. Yours. // Works in React, Vue, Svelte, Astro
CMS bindings,
schema-first.
Framer's CMS is a closed database. The CLI reads every collection schema, field type, and component binding — then exports a portable JSON schema compatible with Contentful, Sanity, Airtable, or a flat-file MDX pipeline.
{
"collection": "blog-posts",
"fields": {
"title": { "type": "string", "required": true },
"slug": { "type": "slug", "source": "title" },
"body": { "type": "rich-text", "format": "MDX" },
"coverImg": { "type": "image", "cdn": "framer-cdn" }
}
}| Collection | Fields | Bindings | Content Type | Export Target | Status |
|---|---|---|---|---|---|
| Blog Posts | 12 | 8 | rich-text | MDX / JSON | mapped |
| Team Members | 7 | 5 | image+text | JSON / Contentful | mapped |
| Case Studies | 18 | 14 | nested | JSON / Sanity | review |
| Products | 22 | 19 | e-commerce | JSON / Shopify | mapped |
| Testimonials | 5 | 4 | simple | JSON | mapped |
| Events | 9 | 7 | date+media | JSON / Airtable | review |
Responsive logic,
every override.
Framer stores breakpoint overrides as invisible property deltas. The CLI diffs every viewport, surfaces hidden elements, size overrides, and layout shifts — then emits clean CSS media queries or Tailwind config.
Read the Full Spec Online →| Viewport | Range | Components | Overrides | Hidden | CSS Output |
|---|---|---|---|---|---|
| Desktop | ≥ 1280px | 247 | 34 | 12 | @media (min-width: 1280px) |
| Laptop | ≥ 1024px | 247 | 28 | 8 | @media (min-width: 1024px) |
| Tablet | ≥ 768px | 247 | 51 | 19 | @media (min-width: 768px) |
| Mobile L | ≥ 390px | 247 | 67 | 31 | @media (min-width: 390px) |
| Mobile S | < 390px | 247 | 72 | 38 | @media (max-width: 389px) |
| Filename | Size | Type | CDN Origin | Portable |
|---|---|---|---|---|
| hero-bg.webp | 340 KB | image | framer-cdn | yes |
| logo-full.svg | 4.2 KB | vector | framer-cdn | yes |
| team-photo-01.jpg | 128 KB | image | framer-cdn | yes |
| custom-font.woff2 | 72 KB | font | framer-cdn | yes |
| product-3d.glb | 1.8 MB | 3d | framer-cdn | review |
| bg-video.mp4 | 4.1 MB | video | framer-cdn | review |
Full surface area.
Nothing left inside.
The last thing Framer hides is its deploy config — API keys, project IDs, CMS endpoints, custom domain bindings. The CLI extracts all 18 environment variables, maps them to portable equivalents, and generates a framework-specific scaffold.
| Variable | Value | Category | Portable Target |
|---|---|---|---|
| FRAMER_PROJECT_ID | abc123xyz | auth | ENV file / CI secret |
| FRAMER_API_KEY | •••••••••• | auth | ENV file / CI secret |
| NEXT_PUBLIC_SITE_URL | mysite.framer.app | routing | Vercel / Netlify env |
| CMS_COLLECTION_ID | col_blog_01 | cms | Contentful / Sanity |
| CUSTOM_DOMAIN | brand.com | routing | DNS + CDN config |
| ANALYTICS_SCRIPT | ga4://G-XXXX | tracking | next/script inject |
Every screw labeled.
Every cable color-coded.
You've seen what the CLI extracts. 247 components, 89 interactions, 34 CMS collections, 5 viewports, 1,200 assets, 18 config variables. Nothing stays inside Framer.