Tutorial

Cursor + Design Tokens Setup Guide

Step-by-step guide to integrate FramingUI design tokens with Cursor IDE for AI-powered UI generation.

FramingUI Team4 min read

Why Cursor Needs Design Tokens

Cursor's AI is powerful at generating code, but without design tokens, it will:

  • Guess color values (bg-blue-500, #3B82F6, rgb(59, 130, 246))
  • Use inconsistent spacing (p-4, px-5, py-3)
  • Create arbitrary border radius values (rounded-md, rounded-lg)

FramingUI solves this by giving Cursor a single source of truth for all design decisions.

Installation

Step 1: Install FramingUI

# Using pnpm (recommended)
pnpm add @framingui/ui @framingui/core

# Using npm
npm install @framingui/ui @framingui/core

# Using yarn
yarn add @framingui/ui @framingui/core

Step 2: Generate Design Tokens

# Interactive mode
npx framingui generate

# Or specify your brand color directly
npx framingui generate --color "#FF6B35"

This creates a .framingui/ directory with your design tokens:

.framingui/
├── tokens.css          # CSS custom properties
├── tokens.json         # JSON format for tooling
└── tailwind.config.js  # Tailwind integration

Step 3: Import Tokens in Your App

// app/layout.tsx (Next.js App Router)
import '@framingui/ui/styles/tokens.css';
import './globals.css';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

Cursor Configuration

Create .cursorrules File

Create a .cursorrules file in your project root:

# FramingUI Design System Rules

## 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:

### Colors
- Primary: var(--tekton-bg-primary)
- Secondary: var(--tekton-bg-secondary)
- Destructive: var(--tekton-bg-destructive)
- Muted: var(--tekton-bg-muted)
- Accent: var(--tekton-bg-accent)
- Card: var(--tekton-bg-card)
- Popover: var(--tekton-bg-popover)

### Spacing
- var(--tekton-spacing-1) through var(--tekton-spacing-8)
- Use these instead of Tailwind's p-1, p-2, etc.

### Border Radius
- var(--tekton-radius-sm)
- var(--tekton-radius-md)
- var(--tekton-radius-lg)
- var(--tekton-radius-xl)

### Borders
- var(--tekton-border-default)
- var(--tekton-border-input)
- var(--tekton-border-ring)

## Code Generation Rules
1. Never hardcode colors - always use var(--tekton-*)
2. Import components from @framingui/ui, not local files
3. Use semantic token names (primary, secondary) not color names (blue, red)
4. Prefer FramingUI components over raw HTML elements
5. Use Tailwind classes that reference tokens: bg-[var(--tekton-bg-primary)]

## Example Component
```tsx
import { Button, Card, CardHeader, CardTitle, CardContent } from '@framingui/ui';

export function ExampleCard() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Example</CardTitle>
      </CardHeader>
      <CardContent className="space-y-[var(--tekton-spacing-4)]">
        <p className="text-[var(--tekton-bg-muted-foreground)]">
          Card content here
        </p>
        <Button variant="default">Click me</Button>
      </CardContent>
    </Card>
  );
}

### VSCode Settings (for Cursor)

Add to `.vscode/settings.json`:

```json
{
  "editor.quickSuggestions": {
    "strings": true
  },
  "css.customData": [".vscode/css-custom-data.json"]
}

Create .vscode/css-custom-data.json for token autocomplete:

{
  "version": 1.1,
  "properties": [
    {
      "name": "--tekton-bg-primary",
      "description": "Primary background color"
    },
    {
      "name": "--tekton-bg-secondary",
      "description": "Secondary background color"
    },
    {
      "name": "--tekton-spacing-4",
      "description": "1rem spacing (16px)"
    },
    {
      "name": "--tekton-radius-md",
      "description": "Medium border radius"
    }
  ]
}

Testing Cursor Integration

Test 1: Generate a Login Form

Ask Cursor:

Create a login form using FramingUI components with email and password fields

Expected output:

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-[var(--tekton-spacing-4)]">
        <div className="space-y-[var(--tekton-spacing-2)]">
          <Label htmlFor="email">Email</Label>
          <Input id="email" type="email" placeholder="you@example.com" />
        </div>
        <div className="space-y-[var(--tekton-spacing-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 colors, uses var(--tekton-*) tokens

Test 2: Generate a Dashboard Card

Ask Cursor:

Create a stats card showing total users with an icon and value

Expected output:

import { Card, CardContent } from '@framingui/ui';
import { Users } from 'lucide-react';

export function StatsCard() {
  return (
    <Card>
      <CardContent className="p-[var(--tekton-spacing-6)]">
        <div className="flex items-center space-x-[var(--tekton-spacing-4)]">
          <div className="p-[var(--tekton-spacing-3)] bg-[var(--tekton-bg-primary)]/10 rounded-[var(--tekton-radius-lg)]">
            <Users className="w-6 h-6 text-[var(--tekton-bg-primary)]" />
          </div>
          <div>
            <p className="text-sm text-[var(--tekton-bg-muted-foreground)]">Total Users</p>
            <p className="text-2xl font-bold">12,345</p>
          </div>
        </div>
      </CardContent>
    </Card>
  );
}

Verify: Uses FramingUI Card, references design tokens

Troubleshooting

Issue: Cursor generates Tailwind classes without tokens

Solution: Update .cursorrules and explicitly ask:

Generate a button using FramingUI and var(--tekton-*) tokens

Issue: Token autocomplete not working

Solution: Restart Cursor after adding .vscode/css-custom-data.json

Issue: Components not found

Solution: Verify package installation:

pnpm list @framingui/ui

Advanced: Custom Token Extensions

You can extend FramingUI tokens for project-specific needs:

/* globals.css */
@import '@framingui/ui/styles/tokens.css';

:root {
  /* Extend with custom tokens */
  --my-app-header-height: 64px;
  --my-app-sidebar-width: 280px;

  /* Override FramingUI tokens (optional) */
  --tekton-radius-xl: 16px;
}

Next Steps

  1. Configure Cursor: Add .cursorrules to your project
  2. Test generation: Ask Cursor to create components
  3. Verify consistency: Check that all generated code uses tokens
  4. Iterate: Refine your rules based on Cursor's output

With FramingUI + Cursor, you get AI-powered UI generation with 0% hallucination on design decisions.

Ready to build with FramingUI?

Join the beta and get early access to agentic design systems that adapt to your needs.

Join Beta
Share

Related Posts