2. Describe the bug
motion and framer-motion declare react and react-dom as optional peer dependencies, but not @types/react. Their type files import React:
import * as React from "react"
Under a strict, non-hoisted node_modules, those type files cannot resolve React's types. Every motion component's props degrade and TypeScript reports:
error TS2607: JSX element class does not support attributes because it does not have a 'props' property
3. IMPORTANT: Provide a CodeSandbox reproduction of the bug
Not possible here, and I want to be upfront about that rather than link something that does not show the problem. CodeSandbox installs with a hoisted node_modules, which is exactly the layout that hides this bug. It only appears under a strict linker: Bun isolated, pnpm, or Yarn PnP.
The local reproduction is four files:
// package.json
{
"devDependencies": {
"motion": "13.1.1",
"react": "^19",
"react-dom": "^19",
"@types/react": "^19",
"typescript": "^5"
}
}
# bunfig.toml
[install]
linker = "isolated"
// tsconfig.json
{ "compilerOptions": { "jsx": "react-jsx", "strict": true, "noEmit": true, "moduleResolution": "bundler", "module": "esnext" } }
// a.tsx
import { motion } from "motion/react"
export const A = () => <motion.div className="x" />
4. Steps to reproduce
bun install
npx tsc -p .
5. Expected behavior
Types resolve and the file compiles.
7. Environment details
macOS 26.5, Bun 1.4.0, React 19.2, TypeScript 5.9. Also reproduces with pnpm.
Why it happens
A strict linker symlinks each package into a store. Node and TypeScript resolve a symlink to its real path before walking parent directories, so a package sees only what it declares. react is declared and resolves; @types/react is not, so it does not.
skipLibCheck suppresses the errors inside motion's own .d.ts files, but not the broken types they hand to consumers.
Suggested fix
Add @types/react alongside the existing optional peers in packages/motion and packages/framer-motion:
"peerDependencies": {
"@types/react": "*"
},
"peerDependenciesMeta": {
"@types/react": { "optional": true }
}
Same pattern @radix-ui/* and posthog-js@1.422.5 already ship. Happy to open the PR.
2. Describe the bug
motionandframer-motiondeclarereactandreact-domas optional peer dependencies, but not@types/react. Their type files import React:Under a strict, non-hoisted
node_modules, those type files cannot resolve React's types. Every motion component's props degrade and TypeScript reports:3. IMPORTANT: Provide a CodeSandbox reproduction of the bug
Not possible here, and I want to be upfront about that rather than link something that does not show the problem. CodeSandbox installs with a hoisted
node_modules, which is exactly the layout that hides this bug. It only appears under a strict linker: Bun isolated, pnpm, or Yarn PnP.The local reproduction is four files:
4. Steps to reproduce
bun installnpx tsc -p .5. Expected behavior
Types resolve and the file compiles.
7. Environment details
macOS 26.5, Bun 1.4.0, React 19.2, TypeScript 5.9. Also reproduces with pnpm.
Why it happens
A strict linker symlinks each package into a store. Node and TypeScript resolve a symlink to its real path before walking parent directories, so a package sees only what it declares.
reactis declared and resolves;@types/reactis not, so it does not.skipLibChecksuppresses the errors inside motion's own.d.tsfiles, but not the broken types they hand to consumers.Suggested fix
Add
@types/reactalongside the existing optional peers inpackages/motionandpackages/framer-motion:Same pattern
@radix-ui/*andposthog-js@1.422.5already ship. Happy to open the PR.