Loading...
Loading...
Create Framer Code Components and Code Overrides. Use when building custom React components for Framer, writing Code Overrides (HOCs) to modify canvas elements, implementing property controls, working with Framer Motion animations, handling WebGL/shaders in Framer, or debugging Framer-specific issues like hydration errors and font handling.
npx skill4agent add fredm00n/framerlabs framer-code-components-overridesaddPropertyControlsaddPropertyControls/**
* @framerDisableUnlink
* @framerIntrinsicWidth 100
* @framerIntrinsicHeight 100
*/@framerDisableUnlink@framerIntrinsicWidth@framerIntrinsicHeight@framerSupportedLayoutWidth@framerSupportedLayoutHeightanyautofixedany-prefer-fixedimport type { ComponentType } from "react"
import { useState, useEffect } from "react"
/**
* @framerDisableUnlink
*/
export function withFeatureName(Component): ComponentType {
return (props) => {
// State and logic here
return <Component {...props} />
}
}withFeatureNameimport { motion } from "framer-motion"
import { addPropertyControls, ControlType } from "framer"
/**
* @framerDisableUnlink
* @framerIntrinsicWidth 300
* @framerIntrinsicHeight 200
*/
export default function MyComponent(props) {
const { style } = props
return <motion.div style={{ ...style }}>{/* content */}</motion.div>
}
MyComponent.defaultProps = {
// Always define defaults
}
addPropertyControls(MyComponent, {
// Controls here
})// ❌ BROKEN - Will not work
style={{
fontFamily: props.font.fontFamily,
fontSize: props.font.fontSize,
}}
// ✅ CORRECT - Spread entire object
style={{
...props.font,
}}font: {
type: ControlType.Font,
controls: "extended",
defaultValue: {
fontFamily: "Inter",
fontWeight: 500,
fontSize: 16,
lineHeight: "1.5em",
},
}startTransition()import { startTransition } from "react"
// ❌ WRONG - May cause issues in Framer's rendering pipeline
setCount(count + 1)
// ✅ CORRECT - Always wrap state updates
startTransition(() => {
setCount(count + 1)
})const [isClient, setIsClient] = useState(false)
useEffect(() => {
setIsClient(true)
}, [])
if (!isClient) {
return <Component {...props} /> // SSR-safe fallback
}
// Client-only logic herewindowdocumentnavigatorlocalStoragesessionStoragewindow.innerWidthwindow.innerHeightimport { RenderTarget } from "framer"
const isOnCanvas = RenderTarget.current() === RenderTarget.canvas
// Show debug only in editor
{isOnCanvas && <DebugOverlay />}export function withVariantControl(Component): ComponentType {
return (props) => {
const [currentVariant, setCurrentVariant] = useState("variant-1")
// Logic to change variant
setCurrentVariant("variant-2")
return <Component {...props} variant={currentVariant} />
}
}overflow: scrollconst observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting && !hasEntered) {
setHasEntered(true)
}
})
},
{ threshold: 0.1 }
)import { Component } from "package-name"import { Component } from "https://esm.sh/package-name@1.2.3?external=react,react-dom"?external=react,react-dom| Issue | Cause | Fix |
|---|---|---|
| Font styles not applying | Accessing font props individually | Spread entire font object: |
| Hydration mismatch | Browser API in render | Use |
| Override props undefined | Expecting property controls | Overrides don't support |
| Scroll animation broken | | Use IntersectionObserver on viewport |
| Shader attach error | Null shader from compilation failure | Check |
| Component display name | Need custom name in Framer UI | |
TypeScript | Using | Use |
touchAction: "none"useEffect(() => {
if (isClient && props.children) {
const timer = setTimeout(() => {
processContent(props.children)
}, 100)
return () => clearTimeout(timer)
}
}, [isClient, props.children])const processChildren = (children) => {
if (typeof children === "string") {
return processText(children)
}
if (isValidElement(children)) {
return cloneElement(children, {
...children.props,
children: processChildren(children.props.children)
})
}
if (Array.isArray(children)) {
return children.map(child => processChildren(child))
}
return children
}<motion.div
style={{
position: "absolute",
left: `${offset}px`, // Static positioning
x: animatedValue, // Animation transform
}}
/>// Up: snappy pop
transition={{ duration: 0.15, ease: [0, 0, 0.39, 2.99] }}
// Down: smooth settle
transition={{ duration: 0.15, ease: [0.25, 0.46, 0.45, 0.94] }}style={{
willChange: "transform",
transform: "translateZ(0)",
backfaceVisibility: "hidden",
}}