Framer Component Best Practices
Best practices for building and improving React components in Framer with property controls, animations, and accessibility.
Core Rules
Component Structure
import { addPropertyControls, ControlType } from "framer";
import { motion } from "framer-motion"; // NOT from "framer"
interface MyComponentProps {
/* typed props */
}
/**
* @framerSupportedLayoutWidth any-prefer-fixed
* @framerSupportedLayoutHeight any-prefer-fixed
*/
export default function MyComponent(props: MyComponentProps) {
// component
}
addPropertyControls(MyComponent, {
/* controls */
});
Platform Constraints
These will cause errors if violated:
- Single file, default export - Use named
function syntax (not arrow functions), no named exports
- Imports - Only
react, react-dom, framer, framer-motion. Import motion from "framer-motion", not "framer"
- Position - Use
position: relative on the root element, never fixed
- SSR - Guard
window/document access: if (typeof window !== "undefined")
- Annotations - Include
@framerSupportedLayoutWidth/Height in a /** */ block comment immediately above the component function
- Types - Provide a typed props interface (e.g.
MyComponentProps). Avoid NodeJS types like Timeout — use number instead
Layout Annotations
| Content |
Width |
Height |
| No intrinsic size |
fixed |
fixed |
| Text/auto-sizing |
auto |
auto |
| Flexible |
any-prefer-fixed |
any-prefer-fixed |
Detect auto vs fixed sizing: check if style.width or style.height is "100%".
Property Controls
To make components configurable in Framer's properties panel, add property controls:
- To make colors customizable, use
ControlType.Color. Reuse the same prop for elements sharing a color.
- To make text styling customizable, use
ControlType.Font with controls: "extended" and defaultFontType: "sans-serif".
- For images, use
ControlType.ResponsiveImage. Set defaults in the component body via destructuring (the control doesn't support defaultValue).
- Provide a
defaultValue for every prop so components render correctly in the Framer canvas. Include at least one item in ControlType.Array controls.
ComponentName.defaultProps is not supported in Framer — use defaultValue on the property control instead.
- Use
hidden for conditional visibility: hidden: (props) => !props.showFeature
- Prefer sliders over steppers unless step values are large.
- Keep controls focused — make key elements configurable, hardcode the rest.
- See Property Control Guide for detailed patterns, font styling rules, and recommended default values.
Image Defaults (in component body)
const {
image = {
src: "https://framerusercontent.com/images/GfGkADagM4KEibNcIiRUWlfrR0.jpg",
alt: "Default",
},
} = props;
Animation Performance
import { useIsStaticRenderer } from "framer";
import { useInView } from "framer-motion";
const isStatic = useIsStaticRenderer();
const ref = useRef(null);
const isInView = useInView(ref);
if (isStatic) return <StaticPreview />; // Show useful static state
// Pause animations when out of viewport
- For very complex animations, consider WebGL instead of
framer-motion.
- Static preview should include visual effects, not just text.
- Wrapping state updates in
startTransition() prevents UI blocking and keeps interactions smooth.
Text
- For auto-sized components with text, apply
width: max-content or minWidth: max-content to prevent text from collapsing.
Common Errors
- WebGL cross-origin: handle
SecurityError: Failed to execute 'texImage2D' for cross-origin images.
- Inverted Y-axis: check if WebGL images render upside down and accommodate.
Accessibility
aria roles on interactive elements
- Semantic HTML (
<nav>, <article>, <section>)
alt="" on decorative images
- 4.5:1 color contrast
Term Interpretation
- "responsive" → width/height 100%
- "modern" → 8px radius, 16px spacing, subtle shadows
- "minimal" → limited colors, whitespace
- "interactive" → hover/active states
- "accessible" → ARIA, semantic HTML
- "props"/"properties" → Framer property controls
Reference Files
- Property Controls - All ControlType documentation with examples
- Property Control Types - TypeScript interfaces for all control types
- Property Control Guide - Font patterns, styling rules, and recommended default values
- Example Components - Cookie banner, image compare, sticky notes, twemoji
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: framer-component-best-practices3description: Best practices for building and improving React code components in Framer, a no-code website builder. Covers property controls, animations, accessibility, and platform constraints. Use when creating, editing, or reviewing Framer components, working with ControlType property controls, or building React components for Framer projects. Use when this capability is needed.4---56# Framer Component Best Practices78Best practices for building and improving React components in Framer with property controls, animations, and accessibility.910## Core Rules1112### Component Structure1314```tsx15import { addPropertyControls, ControlType } from "framer";16import { motion } from "framer-motion"; // NOT from "framer"1718interface MyComponentProps {19 /* typed props */20}2122/**23 * @framerSupportedLayoutWidth any-prefer-fixed24 * @framerSupportedLayoutHeight any-prefer-fixed25 */26export default function MyComponent(props: MyComponentProps) {27 // component28}2930addPropertyControls(MyComponent, {31 /* controls */32});33```3435### Platform Constraints3637These will cause errors if violated:38391. **Single file, default export** - Use named `function` syntax (not arrow functions), no named exports402. **Imports** - Only `react`, `react-dom`, `framer`, `framer-motion`. Import `motion` from `"framer-motion"`, not `"framer"`413. **Position** - Use `position: relative` on the root element, never `fixed`424. **SSR** - Guard `window`/`document` access: `if (typeof window !== "undefined")`435. **Annotations** - Include `@framerSupportedLayoutWidth/Height` in a `/** */` block comment immediately above the component function446. **Types** - Provide a typed props interface (e.g. `MyComponentProps`). Avoid NodeJS types like `Timeout` — use `number` instead4546### Layout Annotations4748| Content | Width | Height |49| ----------------- | ------------------ | ------------------ |50| No intrinsic size | `fixed` | `fixed` |51| Text/auto-sizing | `auto` | `auto` |52| Flexible | `any-prefer-fixed` | `any-prefer-fixed` |5354Detect auto vs fixed sizing: check if `style.width` or `style.height` is `"100%"`.5556### Property Controls5758To make components configurable in Framer's properties panel, add property controls:5960- To make colors customizable, use `ControlType.Color`. Reuse the same prop for elements sharing a color.61- To make text styling customizable, use `ControlType.Font` with `controls: "extended"` and `defaultFontType: "sans-serif"`.62- For images, use `ControlType.ResponsiveImage`. Set defaults in the component body via destructuring (the control doesn't support `defaultValue`).63- Provide a `defaultValue` for every prop so components render correctly in the Framer canvas. Include at least one item in `ControlType.Array` controls.64- `ComponentName.defaultProps` is not supported in Framer — use `defaultValue` on the property control instead.65- Use `hidden` for conditional visibility: `hidden: (props) => !props.showFeature`66- Prefer sliders over steppers unless step values are large.67- Keep controls focused — make key elements configurable, hardcode the rest.68- See [Property Control Guide](references/PROPERTY_CONTROL_GUIDE.md) for detailed patterns, font styling rules, and recommended default values.6970### Image Defaults (in component body)7172```tsx73const {74 image = {75 src: "https://framerusercontent.com/images/GfGkADagM4KEibNcIiRUWlfrR0.jpg",76 alt: "Default",77 },78} = props;79```8081### Animation Performance8283```tsx84import { useIsStaticRenderer } from "framer";85import { useInView } from "framer-motion";8687const isStatic = useIsStaticRenderer();88const ref = useRef(null);89const isInView = useInView(ref);9091if (isStatic) return <StaticPreview />; // Show useful static state92// Pause animations when out of viewport93```9495- For very complex animations, consider WebGL instead of `framer-motion`.96- Static preview should include visual effects, not just text.97- Wrapping state updates in `startTransition()` prevents UI blocking and keeps interactions smooth.9899### Text100101- For auto-sized components with text, apply `width: max-content` or `minWidth: max-content` to prevent text from collapsing.102103### Common Errors104105- WebGL cross-origin: handle `SecurityError: Failed to execute 'texImage2D'` for cross-origin images.106- Inverted Y-axis: check if WebGL images render upside down and accommodate.107108### Accessibility109110- `aria` roles on interactive elements111- Semantic HTML (`<nav>`, `<article>`, `<section>`)112- `alt=""` on decorative images113- 4.5:1 color contrast114115## Term Interpretation116117- "responsive" → width/height 100%118- "modern" → 8px radius, 16px spacing, subtle shadows119- "minimal" → limited colors, whitespace120- "interactive" → hover/active states121- "accessible" → ARIA, semantic HTML122- "props"/"properties" → Framer property controls123124## Reference Files125126- [Property Controls](references/PROPERTY_CONTROLS.md) - All ControlType documentation with examples127- [Property Control Types](references/PROPERTY_CONTROL_TYPES.md) - TypeScript interfaces for all control types128- [Property Control Guide](references/PROPERTY_CONTROL_GUIDE.md) - Font patterns, styling rules, and recommended default values129- [Example Components](references/EXAMPLES.md) - Cookie banner, image compare, sticky notes, twemoji130131---132> Converted and distributed by [TomeVault](https://tomevault.io/claim/framer) — claim your Tome and manage your conversions.133<!-- tomevault:4.0:skill_md:2026-04-11 -->