$npx -y skills add dylantarre/design-system-skills --skill framerIntegrates design tokens with Framer for prototyping and production sites. Use when adding CSS custom properties to Framer projects, creating code components, or building Framer sites with design systems.
| 1 | # Framer Token Integration |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | Integrate design tokens with Framer for consistent prototyping and production sites. Use CSS custom properties, Framer overrides, and code components to bring your design system into Framer. |
| 6 | |
| 7 | ## When to Use |
| 8 | |
| 9 | - Setting up design tokens in Framer |
| 10 | - Creating Framer code components with tokens |
| 11 | - Building interactive prototypes with design system |
| 12 | - Publishing Framer sites with consistent styling |
| 13 | |
| 14 | ## Quick Reference: Integration Methods |
| 15 | |
| 16 | | Method | Use Case | Complexity | |
| 17 | |--------|----------|------------| |
| 18 | | CSS Variables | Global token import | Simple | |
| 19 | | Code Components | Custom React components | Medium | |
| 20 | | Overrides | Dynamic styling | Simple | |
| 21 | | Framer Library | Shared component library | Advanced | |
| 22 | |
| 23 | ## The Process |
| 24 | |
| 25 | 1. **Export tokens as CSS**: Generate CSS custom properties file |
| 26 | 2. **Import in Framer**: Add to custom code or component |
| 27 | 3. **Create code components**: Build with token references |
| 28 | 4. **Set up overrides**: Apply dynamic styles |
| 29 | 5. **Publish and maintain**: Keep tokens in sync |
| 30 | |
| 31 | --- |
| 32 | |
| 33 | ## CSS Variables in Framer |
| 34 | |
| 35 | ### Global CSS Import |
| 36 | |
| 37 | **In Framer Site Settings → Custom Code → Head:** |
| 38 | ```html |
| 39 | <style> |
| 40 | :root { |
| 41 | /* Colors */ |
| 42 | --color-primary-50: #eff6ff; |
| 43 | --color-primary-100: #dbeafe; |
| 44 | --color-primary-500: #3b82f6; |
| 45 | --color-primary-600: #2563eb; |
| 46 | --color-primary-900: #1e3a8a; |
| 47 | |
| 48 | --color-gray-50: #f9fafb; |
| 49 | --color-gray-100: #f3f4f6; |
| 50 | --color-gray-500: #6b7280; |
| 51 | --color-gray-900: #111827; |
| 52 | |
| 53 | --color-success-500: #22c55e; |
| 54 | --color-warning-500: #f59e0b; |
| 55 | --color-error-500: #ef4444; |
| 56 | |
| 57 | /* Spacing */ |
| 58 | --spacing-xs: 4px; |
| 59 | --spacing-sm: 8px; |
| 60 | --spacing-md: 16px; |
| 61 | --spacing-lg: 24px; |
| 62 | --spacing-xl: 32px; |
| 63 | |
| 64 | /* Typography */ |
| 65 | --text-xs: 12px; |
| 66 | --text-sm: 14px; |
| 67 | --text-base: 16px; |
| 68 | --text-lg: 18px; |
| 69 | --text-xl: 20px; |
| 70 | --text-2xl: 24px; |
| 71 | |
| 72 | /* Border Radius */ |
| 73 | --radius-sm: 4px; |
| 74 | --radius-md: 8px; |
| 75 | --radius-lg: 16px; |
| 76 | --radius-full: 9999px; |
| 77 | |
| 78 | /* Shadows */ |
| 79 | --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); |
| 80 | --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1); |
| 81 | --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1); |
| 82 | } |
| 83 | |
| 84 | /* Dark mode */ |
| 85 | [data-framer-theme="dark"] { |
| 86 | --color-background: var(--color-gray-900); |
| 87 | --color-foreground: var(--color-gray-50); |
| 88 | } |
| 89 | </style> |
| 90 | ``` |
| 91 | |
| 92 | ### External CSS File |
| 93 | |
| 94 | **Link your token CSS file:** |
| 95 | ```html |
| 96 | <link rel="stylesheet" href="https://your-cdn.com/tokens.css"> |
| 97 | ``` |
| 98 | |
| 99 | --- |
| 100 | |
| 101 | ## Code Components |
| 102 | |
| 103 | ### Button Component |
| 104 | |
| 105 | **Button.tsx (Framer Code Component):** |
| 106 | ```tsx |
| 107 | import { addPropertyControls, ControlType } from "framer" |
| 108 | import { motion } from "framer-motion" |
| 109 | |
| 110 | interface ButtonProps { |
| 111 | text: string |
| 112 | variant: "primary" | "secondary" | "ghost" | "danger" |
| 113 | size: "sm" | "md" | "lg" |
| 114 | fullWidth: boolean |
| 115 | disabled: boolean |
| 116 | onClick?: () => void |
| 117 | } |
| 118 | |
| 119 | export function Button({ |
| 120 | text = "Button", |
| 121 | variant = "primary", |
| 122 | size = "md", |
| 123 | fullWidth = false, |
| 124 | disabled = false, |
| 125 | onClick, |
| 126 | }: ButtonProps) { |
| 127 | const sizeStyles = { |
| 128 | sm: { |
| 129 | height: 32, |
| 130 | padding: "0 var(--spacing-sm)", |
| 131 | fontSize: "var(--text-sm)", |
| 132 | }, |
| 133 | md: { |
| 134 | height: 40, |
| 135 | padding: "0 var(--spacing-md)", |
| 136 | fontSize: "var(--text-base)", |
| 137 | }, |
| 138 | lg: { |
| 139 | height: 48, |
| 140 | padding: "0 var(--spacing-lg)", |
| 141 | fontSize: "var(--text-lg)", |
| 142 | }, |
| 143 | } |
| 144 | |
| 145 | const variantStyles = { |
| 146 | primary: { |
| 147 | backgroundColor: "var(--color-primary-500)", |
| 148 | color: "white", |
| 149 | border: "none", |
| 150 | }, |
| 151 | secondary: { |
| 152 | backgroundColor: "transparent", |
| 153 | color: "var(--color-gray-700)", |
| 154 | border: "1px solid var(--color-gray-300)", |
| 155 | }, |
| 156 | ghost: { |
| 157 | backgroundColor: "transparent", |
| 158 | color: "var(--color-gray-700)", |
| 159 | border: "none", |
| 160 | }, |
| 161 | danger: { |
| 162 | backgroundColor: "var(--color-error-500)", |
| 163 | color: "white", |
| 164 | border: "none", |
| 165 | }, |
| 166 | } |
| 167 | |
| 168 | const hoverStyles = { |
| 169 | primary: { backgroundColor: "var(--color-primary-600)" }, |
| 170 | secondary: { backgroundColor: "var(--color-gray-50)" }, |
| 171 | ghost: { backgroundColor: "var(--color-gray-100)" }, |
| 172 | danger: { backgroundColor: "var(--color-error-600)" }, |
| 173 | } |
| 174 | |
| 175 | return ( |
| 176 | <motion.button |
| 177 | style={{ |
| 178 | ...sizeStyles[size], |
| 179 | ...variantStyles[variant], |
| 180 | width: fullWidth ? "100%" : "auto", |
| 181 | display: "inline-flex", |
| 182 | alignItems: "center", |
| 183 | justifyContent: "center", |
| 184 | gap: "var(--spacing-xs)", |
| 185 | borderRadius: "var(--radius-md)", |
| 186 | fontWeight: 500, |
| 187 | cursor: disabled ? "not-allowed" : "pointer", |
| 188 | opacity: disabled ? 0.5 : 1, |
| 189 | fontFamily: "inherit", |
| 190 | outline: "none", |
| 191 | }} |
| 192 | whileHover={disabled ? {} : hoverStyles[variant]} |
| 193 | whileTap={disabled ? {} : { scale: 0.98 }} |
| 194 | onClick |