Cursor generates a notification card in five seconds. You spend five minutes correcting the colors, padding, and border radius to match your design system. That ratio — five seconds to generate, five minutes to fix — is the problem this guide solves.
The fix is a .cursorrules file. It takes fifteen minutes to set up and eliminates most of the manual correction work.
Why Cursor Guesses Wrong
Without explicit rules, Cursor pulls from its training data: popular open-source repos, public component libraries, generic Tailwind patterns. It has no idea that your project uses indigo-600 not blue-600, p-6 not p-4, or bg-neutral-50 not bg-white.
FramingUI's design tokens are CSS variables — var(--bg-primary-default), var(--foreground-primary), var(--foreground-accent) — not JavaScript objects or hardcoded hex values. Cursor won't use them unless you tell it to.
Installation
Install the packages with pnpm:
pnpm add @framingui/ui @framingui/core @framingui/tokens tailwindcss-animate
Import the styles in your app's global layout:
// app/layout.tsx (Next.js App Router)
import '@framingui/ui/styles';
import './globals.css';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
Cursor Configuration
Create .cursorrules
Create .cursorrules in your project root. This file is Cursor's instruction manual for your codebase.
# Design System: FramingUI
## Component Library
Always import UI components from @framingui/ui:
- Button, Input, Card, Form, Dialog, Sheet, Tabs
- Label, Checkbox, RadioGroup, Select, Switch
- Table, Avatar, Badge, Tooltip, Popover
## Design Tokens
Use CSS custom properties for all styling. Never hardcode colors or spacing.
### Colors
- Primary background: var(--background-page)
- Primary text: var(--foreground-primary)
- Action primary: var(--foreground-accent)
- Muted text: var(--foreground-muted)
### Spacing
Use Tailwind classes that reference tokens:
- bg-[var(--background-page)]
- text-[var(--foreground-primary)]
## Code Generation Rules
1. Never hardcode colors — always use var(--*)
2. Import components from @framingui/ui, not local files
3. Use semantic token names, not color names (blue, red)
4. Prefer FramingUI components over raw HTML elements
## Example Component
```tsx
import { Button, Card, CardHeader, CardTitle, CardContent } from '@framingui/ui';
export function ExampleCard() {
return (
<Card>
<CardHeader>
<CardTitle>Example</CardTitle>
</CardHeader>
<CardContent>
<Button variant="default">Click me</Button>
</CardContent>
</Card>
);
}
### VSCode Settings for Token Autocomplete
Add to `.vscode/settings.json`:
```json
{
"editor.quickSuggestions": {
"strings": true
},
"css.customData": [".vscode/css-custom-data.json"]
}
Create .vscode/css-custom-data.json:
{
"version": 1.1,
"properties": [
{
"name": "--background-page",
"description": "Primary canvas background"
},
{
"name": "--foreground-primary",
"description": "Primary text color"
},
{
"name": "--foreground-accent",
"description": "Primary action / brand color"
}
]
}
Restart Cursor after creating this file.
Testing the Integration
Ask Cursor: "Create a login form using FramingUI components with email and password fields."
A correctly configured Cursor should produce something like this:
import { Button, Input, Label, Card, CardHeader, CardTitle, CardContent } from '@framingui/ui';
export function LoginForm() {
return (
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle>Sign In</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" placeholder="[email protected]" />
</div>
<div className="space-y-2">
<Label htmlFor="password">Password</Label>
<Input id="password" type="password" />
</div>
<Button className="w-full" variant="default">
Sign In
</Button>
</CardContent>
</Card>
);
}
Verify: no hardcoded hex values, components imported from @framingui/ui, no arbitrary Tailwind color classes.
Troubleshooting
Cursor generates raw Tailwind without tokens: Update your .cursorrules and add explicit examples. Be specific: "Use bg-[var(--background-page)] not bg-white."
Token autocomplete not working: Restart Cursor after adding .vscode/css-custom-data.json. The file must exist before Cursor starts.
Components not found: Verify installation with pnpm list @framingui/ui. If missing, rerun the install command.
Extending the Token System
You can layer project-specific tokens on top of the FramingUI base:
/* globals.css */
@import '@framingui/ui/styles';
:root {
--my-app-header-height: 64px;
--my-app-sidebar-width: 280px;
}
Add these to your .cursorrules and .vscode/css-custom-data.json so Cursor knows about them.
The fifteen-minute setup pays back on the first complex component Cursor generates correctly. Every component after that is compounding return.